vim-vebugger/doc/vebugger.txt

476 lines
20 KiB
Plaintext
Raw Normal View History

2014-05-17 15:43:18 -04:00
*vebugger.txt*
2014-06-04 12:45:39 -04:00
Author: Idan Arye <https://github.com/idanarye/>
2014-05-17 15:43:18 -04:00
License: Same terms as Vim itself (see |license|)
2014-08-29 17:41:13 -04:00
Version: 1.2.0
2014-05-17 15:43:18 -04:00
INTRODUCTION *vebugger*
Vebugger is yet another debugger frontend plugin for Vim, created because I
wasn't happy with the other debugger plugins I found. Vebugger currently
supports:
* Tracking the currently executed command in the source code
* Debugger flow commands - step-in, set-over, set-out and continue
* Breakpoints management
* Evaluating expressions in the current executed scope
* Messing with the program's state(changing values, calling functions)
Vebugger is built as a generic framework for building frontends for
interactive shell debugger, and comes with implementations for:
* GDB - doesn't need introdcution...
* JDB - a Java debugger
* Mdbg - a .NET debugger(Windows only)
2014-05-17 15:43:18 -04:00
* PDB - a Python module for debugging Python scripts
* RDebug - a Ruby command line option for debugging Ruby scripts
Other implementations can be added with ease, and I will accept pull requests
that add such implementations as long as they use Vim's |license|.
2014-05-17 15:43:18 -04:00
Vebugger is built under the following assumptions:
* While command line debuggers share enough in common to make the creation
of such a framework as Vebugger possible, the differences between them are
too great to be expressed with regular expression. To support them all at
least some code has to be written.
* Unlike IDE users, Vim users tend to understand the tools the operate behind
the scenes. While Vebugger automates the common features, it allows you to
"open the hood" and interact with the debugger's shell directly so you could
utilize the full power of your debugger.
* I have no intention to aim for the lowest common denominator. If one
debugger has a cool feature I want to support, I'll implement it even if the
other debuggers don't have it.
Vebugger is developed under Linux. It doesn't work properly under Windows due
to lack of PTY support. I have neither plans nor means to support OSX, but I
will accept pull requests that add OSX support.
The features that don't work under windows are:
* RDebug.
* Displaying output from the debugged program.
REQUIREMENTS *vebugger-requirements*
Vebugger requires the vimproc plugin, obtainable from:
https://github.com/Shougo/vimproc.vim
Notice that vimproc needs to be built - there are instructions in the GitHub
page.
In order for Vebugger to use a debugger, that debugger must be installed and
it's executable must either be in the PATH or set with a global variable (see
|vebugger-configuration|). In case of RDebug and PDB, which are used from the
Ruby and Python modules, the interpreter("ruby" or "python") is the one that
must be installed and in the path.
2014-05-17 15:43:18 -04:00
CONFIGURATION *vebugger-configuration*
If you want to use the keymaps, you need to choose a leader for them by
setting *g:vebugger_leader* in your vimrc.
Example: >
let g:vebugger_leader='<Leader>d'
<
If a debugger is not in the PATH you can set the direct path to it by setting
g:vebugger_path_XXX, where XXX is the executable used for the debugger:
*g:vebugger_path_gdb* defaults to "gdb"
*g:vebugger_path_jdb* defaults to "jdb"
*g:vebugger_path_mdbg* defaults to "Mdbg.exe"
*g:vebugger_path_python* defaults to "python"
*g:vebugger_path_ruby* defaults to "ruby"
Notice that for PDB and RDebug you use "python" and "ruby", since the debugger
is actually a module bundled in the interpreter.
You can set multiple versions for each debugger, by appending the version name
to the debugger name with "_". These versions will be used when the "version"
argument is supplied when running the debugger:
*g:vebugger_path_python_2* defaults to "python2"
*g:vebugger_path_python_3* defaults to "python3"
*g:vebugger_path_mdbg_32* No default - use it for the 32bit version of Mdbg
*g:vebugger_path_mdbg_64* No default - use it for the 64bit version of Mdbg
2014-05-17 15:43:18 -04:00
LAUNCHING DEBUGGERS *vebugger-launching*
A debugger's implementation is responsible for starting it. The standard is to
have a "start" function that accepts two arguments: The file to launch(EXE
file or main script file) and a dictionary of other arguments. There should
also be a command for launching the debugger with more ease.
It should go without saying that you can't debug an executable that's not
debuggable with the debugger you use, and you won't get meaningful results if
you try to debug binary/bytecode files that were compiled without debugging
information(usually the "-g" flag).
2014-05-17 15:43:18 -04:00
LAUNCHING GDB *vebugger-gdb*
GDB can be launched with *vebugger#gdb#start*
2014-05-17 15:43:18 -04:00
>
call vebugger#gdb#start('a.out',{'args':['hello','world']})
<
The supported extra arguments are:
* "args": Command line arguments for the debugged program
* "pid": Process id to attach to
* "entry": The entry point for starting the debugging(default "main")
* "version": The version of the debugger to run
You can't specify both ("args" and/or "entry") and "pid".
2014-05-17 15:43:18 -04:00
GDB can also be launched with the *VBGstartGDB* command:
>
VBGstartGDB a.out hello world
<
The *VBGattachGDB* command searches for processes launched from the EXE to
attach to, and attaches to them:
>
VBGattachGDB a.out
<
The *VBGstartGDBForD* command is the same as VBGstartGDB but for Dlang
programs.
2014-05-17 15:43:18 -04:00
LAUNCHING JDB *vebugger-jdb*
JDB is launched with *vebugger#jdb#start*
>
call vebugger#jdb#start('Main',{
\'classpath':'classes',
\'srcpath':'src',
\'args':['hello','world']})
<
Unlike in the other debuggers, the first argument here is not the name of a
file - it's the name of the class to run. The supported extra arguments are:
* "args": Command line arguments for the debugged program
* "classpath": Where to look for class files
* "srcpath": Where to look for source files
* "version": The version of the debugger to run
2014-05-17 15:43:18 -04:00
If you don't supply "classpath" and "srcpath", Vebugger will assume you are
using the current directory for source files and class files.
JDB does not have a command for starting it, since you usually want to supply
"classpath" and "srcpath".
LAUNCHING RDEBUG *vebugger-rdebug*
RDebug is launched with *vebugger#rdebug#start*
>
call vebugger#rdebug#start('script.rb',{'args':['hello','world']})
<
The supported extra arguments are:
* "args": Command line arguments for the debugged script
* "version": The version of the debugger to run
2014-05-17 15:43:18 -04:00
RDebug can also be launched with the *VBGstartRDebug* command:
>
VBGstartRDebug script.rb hello world
<
LAUNCHING PDB *vebugger-pdb*
PDB is launched with *vebugger#pdb#start*
>
call vebugger#pdb#start('script.py',{'args':['hello','world']})
<
The supported extra arguments are:
* "args": Command line arguments for the debugged script
* "version": The version of the debugger to run
2014-05-17 15:43:18 -04:00
PDB can also be launched with the *VBGstartPDB* command:
>
VBGstartPDB script.py hello world
<
There are also commands to specify if you want to use python2 or python3:
>
VBGstartPDB2 script.py hello world
VBGstartPDB3 script.py hello world
<
LAUNCHING MDBG *vebugger-mdbg*
Mdbg is launched with *vebugger#mdbg#start*
>
call vebugger#mdbg#start('App.exe',{
\'srcpath':'src',
\'args':['hello','world']})
<
The supported extra arguments are:
* "srcpath": Where to look for source files
* "noConsole": If non-zero, do not open a console for the debugged program
* "args": Command line arguments for the debugged program
* "pid": Process id to attach to
* "version": The version of the debugger to run
If you specify "pid", you can't specify "args" and/or "noConsole".
If you don't supply "srcpath", Vebugger will assume you are
using the current directory for source files.
Mdbg does not have a command for starting it, since you usually want to supply
"srcpath".
You can also search for a process with *vebugger#mdbg#searchAndAttach*
>
call vebugger#mdbg#searchAndAttach('App.exe','src')
<
Here the first argument is the executable and the second is the source files
directory. This will display a list of available processes to attach to.
Notice that unlike GDB, you need "src" here since Mdbg doesn't display full
source file paths.
2014-05-17 15:43:18 -04:00
USING THE DEBUGGERS *vebugger-usage* *vebugger-commands*
Once you have launched a debugger, you can use the following commands to
interact with it:
CONTROL THE EXECUTION OF THE PROGRAM *vebugger-execution-control*
*:VBGstepOver* Continue the execution, stopping at the next statement.
*:VBGstepIn* Same as VBGstepOver but stepps into functions.
*:VBGstepOut* Continue the execution until the end of the current function.
*:VBGcontinue* Continue the execution.
MANAGE BREAKPOINTS *vebugger-breakpoints*
*:VBGtoggleBreakpoint* Toggle a breakpoint. The file and line should be supplied as arguments.
*:VBGtoggleBreakpointThisLine* Toggle a breakpoint for the current line.
*:VBGclearBreakpints* Clear all breakpoints.
EVALUATE EXPRESSIONS *vebugger-evalutate*
*:VBGeval* Evaluate and print the expression supplied as argument.
*:VBGevalSelectedText* Evaluate and print the selected text.
*:VBGevalWordUnderCursor* Evaluate the <cword> under the cursor
EXECUTE STATEMENTS *vebugger-execute*
*:VBGexecute* Execute the statement supplied as argument.
*:VBGexecuteSelectedText* Execute the selected text.
TERMINATING THE DEBUGGER *vebugger-terminate*
*:VBGkill* Terminates the debugger
OPENING THE HOOD *vebugger-open-the-hood*
You can open the hood and interact with the running debugger directly using
the following commands:
*:VBGtoggleTerminalBuffer* Opens a buffer that shows everything printed from
the debugger interactive shell.
*:VBGrawWrite* Sends a line supplied as argument to the debugger interactive shell.
*:VBGrawWriteSelectedText* Sends the selected text to the debugger interactive
shell.
KEYMAPS *vebugger-keymaps*
If you set|g:vebugger_leader| in your vimrc you'll get keymaps for the
Vebugger commands. The keymaps all start with the leader you set, following
with:
i |:VBGstepIn|
o |:VBGstepOver|
O |:VBGstepOut|
c |:VBGcontinue|
b |:VBGtoggleBreakpointThisLine|
B |:VBGclearBreakpints|
e |:VBGevalWordUnderCursor| in normal mode
|:VBGevalSelectedText| in select mode
E Prompt for an argument for |:VBGeval|
x |:VBGexecute| current line in normal mode.
|:VBGexecuteSelectedText| in select mode
X Prompt for an argument for |:VBGexecute|
t |:VBGtoggleTerminalBuffer|
r Select mode only - |:VBGrawWriteSelectedText|
R Prompt for an argument for |:VBGrawWrite|
ARCHITECTURE *vebugger-architecture*
Vebugger architecture is a combination of the Pipeline architecture and the
Message Bus architecture. Vebugger reads lines from the debugger's interactive
shell and creates a read result object. The read handlers look at each line
and populate the read result object. Think handlers look at the read result
and decide what to do with it. They can interact with the user by operate Vim
directly, or they can create write action object. Write handlers look at those
write action objects and write to the debugger's interactive shell's stdin.
This architecture allows flexibility and code reuse. Read and Write handlers
interact with the debugger's interactive shell so they must be debugger
specific, but think handlers use read result and write action objects so they
don't care about the specific debugger. If Vebugger does not support
some feature for some debugger(either because the debugger doesn't support it
or because it's not implemented in Vebugger for this specific debugger) the
think handler can stay and no harm will be done. The read result objects won't
be created so the think handler simply won't get them, and if the think
handler creates a write action object it'll get ignored because there is no
write handler that can handle it for this specific debugger. The think handle
won't crash a debugger that doesn't support it - it'll simply be ignored.
READ RESULT OBJECTS *vebugger-architecture-read-result-objects*
Whenever Vebugger reads a line from the debugger's interactive shell, it
creates a read result object. The read result object does not contain the raw
line - it contains a structure that will be filled with the information parsed
from that raw line by the read handlers.
The read result object starts with a structure defined in the debugger
object's "readResultTemplate" field, which is deep copied to create read
result objects. The direct fields of the read result objects are actually
namespaces. Vebugger only 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 debugger frontend implementation can also define
it's own namespace, but this has limited usage as these implementations
usually don't define think handlers.
READ HANDLERS *vebugger-architecture-read-handlers*
Read handlers are responsible for parsing the raw lines from the debugger's
interactive shell and populating the read result object with the data they
gathered from that line. Each read handler should focus on single type of
output(e.g. current executed line, output from the debugged program, variable
value) and ignore any line that doesn't have that data.
Read handlers are added with the "addReadHandler" method of the debugger object.
That method accepts a VimScript function and creates an object with the
function as it's "handle" method. Alternatively, that object can be created
and passed to the "addReadHandler" method. This architecture means that if a
read handler is declared as a |Dictionary-function| it can utilize the handler
object's state.
A read handler accepts 4 arguments:
1) A string with the name of the pipe the line came from("out" or "err")
2) A string with the line itself
3) The read result object that was created for the line
4) The debugger object
The read handler function should fill the read result object with information
from that line. It should not make assumptions about other read handlers that
parsed that line before or will parse that line after and fill the same read
result objects.
If a read handler needs to parse multiline output, it should use the handler
object's state to store information between calls, and only fill the read
result object once it reads the last line.
THINK HANDLERS *vebugger-architecture-think-handlers*
Think handlers are responsible for operating on the data they get from read
handlers. Think handlers can operate Vim to display data to the user, or
operate the debugger itself(via write actions). Each think handler should have
a single responsibility(e.g. jumping and marking the current executed line,
printing data previously requested by the user) and only operate when the read
result object have the data it needs.
Think handlers are added with the "addThinkHandler" method of the debugger object.
That method accepts a VimScript function and creates an object with the
function as it's "handle" method. Alternatively, that object can be created
and passed to the "addThinkHandler" method. This architecture means that if a
think handler is declared as a |Dictionary-function| it can utilize the handler
object's state.
A think handler accepts 2 arguments:
1) A read result object
2) The debugger object
A think handler interacts with Vim directly, but it should only interact with
the debugger's interactive shell via write actions.
WRITE ACTIONS OBJECTS *vebugger-architecture-write-actions-objects*
A write action is an abstract command to the debugger, that will be converted
to the specific debugger's syntax in the write handlers. A write action can be
created in the think handlers or from the outside. A write actions object can
contain multiple write actions. When the object gets executed, write handlers
handle all the write actions inside it and the write actions object is
replaced by a new one.
The write actions object starts with a structure defined in the debugger
object's "writeActionsTemplate" field, which is deep copied to create write
actions objects. The direct fields of the write actions objects are actually
namespaces. Vebugger only defines the "std" namespace, and plugins built on
top of Vebugger can define a namespaced named after the plugin to contain
their own write actions. A debugger frontend implementation can also define
it's own namespace. The fields of these namespaces are the names of the write
actions themselves. Each write action can either be a list or a dictionary.
This structure is important since it defines the execution of the write
handlers.
Each write action in the write actions object can be a dictionary or a list,
depending on whether multiple actions can be executed in the same time. For
example, a flow control action is a dictionary(you can't do step-in and
step-out at the same time) but a breakpoint management action is a list(you
can set multiple breakpoints in the same time).
Write actions are created with the setWriteAction(for dictionary type actions)
and addWriteAction(for list type actions) methods of the debugger object. Both
methods accept three parameters: a namespace, a name, and the action's
value(usually a dictionary).
WRITE HANDLERS *vebugger-architecture-write-handlers*
Write handlers are responsible for writing commands to the debugger's
interactive shell. Unlike think handlers, which get a whole read result object
and ignore what they don't need, write handlers have one-to-one relationship with
write actions. A write handler will only get the write action it is registered
for, will not be executed if that write action is empty, and only one write
handler can be registered for each write action(namespace+name)
Write handlers are added with the "setWriteAction" method of the debugger
object, which accepts 3 arguments: a namespace, a name, and a VimScript
function and creates an object with the function as it's "handle" method.
Alternatively, that object can be created and passed as the third argument for
the "setWriteAction" method. This architecture means that if a write handler
is declared as a |Dictionary-function| it can utilize the handler object's
state.
A write handler accepts 2 arguments:
1) A single write action(usually object or dictionary)
2) The debugger object
A write handler uses the "writeLine" method of the debugger object to write
lines to the debugger.
CLOSE HANDLERS *vebugger-architecture-close-handlers*
Close handlers are called once the debugger is closed - either it closes
itself or the process is killed. Close handlers can be used to tidy things up.
For example there is a standard close handler that unmarks the currently
executed line.
Close handlers are added with the "addCloseHandler" method of the debugger object.
That method accepts a VimScript function and creates an object with the
function as it's "handle" method. Alternatively, that object can be created
and passed to the "addCloseHandler" method. This architecture means that if a
close handler is declared as a |Dictionary-function| it can utilize the handler
object's state. This is done for consistency with the other types of handlers.
The usefulness of this mechanism for close handlers is limited since they are
only called once and have no use for storing state.
A close handler accepts a single argument - The debugger object.
DEBUGGER STATE *vebugger-architecture-debugger-state*
The debugger object, which is passed as an argument to all handlers, has a
"state" field that can be used for storing data and configuration. This is
mostly useful for think handlers, but other handlers may use it as well(for
example, the JDB read handlers use a configuration field with the source path
to convert the JDB output(that uses class names instead of file names) to
actual paths).
The direct fields of the "state" field are actually namespaces. Vebugger
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
debugger frontend implementation can also define it's own namespace for
storing debugger-specific data and configuration.