vimscript - debug

help: debug-scripts 

Debugging scripts *debug-scripts*

Besides the obvious messages that you can add to your scripts to find out what
they are doing, Vim offers a debug mode. This allows you to step through a
sourced file or user function and set breakpoints.

NOTE: The debugging mode is far from perfect. Debugging will have side
effects on how Vim works. You cannot use it to debug everything. For
example, the display is messed up by the debugging messages.

An alternative to debug mode is setting the 'verbose' option. With a bigger
number it will give more verbose messages about what Vim is doing.


STARTING DEBUG MODE *debug-mode*

To enter debugging mode use one of these methods:
1. Start Vim with the |-D| argument: >
vim -D file.txt
< Debugging will start as soon as the first vimrc file is sourced. This is
useful to find out what is happening when Vim is starting up. A side
effect is that Vim will switch the terminal mode before initialisations
have finished, with unpredictable results.
For a GUI-only version (Windows, Macintosh) the debugging will start as
soon as the GUI window has been opened. To make this happen early, add a
":gui" command in the vimrc file.
*:debug*
2. Run a command with ":debug" prepended. Debugging will only be done while
this command executes. Useful for debugging a specific script or user
function. And for scripts and functions used by autocommands. Example: >
:debug edit test.txt.gz

3. Set a breakpoint in a sourced file or user function. You could do this in
the command line: >
vim -c "breakadd file */explorer.vim" .
< This will run Vim and stop in the first line of the "explorer.vim" script.
Breakpoints can also be set while in debugging mode.

In debugging mode every executed command is displayed before it is executed.
Comment lines, empty lines and lines that are not executed are skipped. When
a line contains two commands, separated by "|", each command will be displayed
separately.


DEBUG MODE

Once in debugging mode, the usual Ex commands can be used. For example, to
inspect the value of a variable: >
echo idx
When inside a user function, this will print the value of the local variable
"idx". Prepend "g:" to get the value of a global variable: >
echo g:idx
All commands are executed in the context of the current function or script.
You can also set options, for example setting or resetting 'verbose' will show
what happens, but you might want to set it just before executing the lines you
are interested in: >
:set verbose=20

Commands that require updating the screen should be avoided, because their
effect won't be noticed until after leaving debug mode. For example: >
:help
won't be very helpful.

There is a separate command-line history for debug mode.

NOTE: In Vim9 script, if a command is written at the script level and
continues on the next line, not using the old way with a backslash for line
continuation, only the first line is printed before the debugging prompt.

The line number for a function line is relative to the start of the function.
If you have trouble figuring out where you are, edit the file that defines
the function in another Vim, search for the start of the function and do
"99j". Replace "99" with the line number.

Additionally, these commands can be used:
*>cont*
cont Continue execution until the next breakpoint is hit.
*>quit*
quit Abort execution. This is like using CTRL-C, some
things might still be executed, doesn't abort
everything. Still stops at the next breakpoint.
*>next*
next Execute the command and come back to debug mode when
it's finished. This steps over user function calls
and sourced files.
*>step*
step Execute the command and come back to debug mode for
the next command. This steps into called user
functions and sourced files.
*>interrupt*
interrupt This is like using CTRL-C, but unlike ">quit" comes
back to debug mode for the next command that is
executed. Useful for testing |:finally| and |:catch|
on interrupt exceptions.
*>finish*
finish Finish the current script or user function and come
back to debug mode for the command after the one that
sourced or called it.
*>bt*
*>backtrace*
*>where*
backtrace Show the call stacktrace for current debugging session.
bt
where
*>frame*
frame N Goes to N backtrace level. + and - signs make movement
relative. E.g., ":frame +3" goes three frames up.
*>up*
up Goes one level up from call stacktrace.
*>down*
down Goes one level down from call stacktrace.

About the additional commands in debug mode:
- There is no command-line completion for them, you get the completion for the
normal Ex commands only.
- You can shorten them, up to a single character, unless more than one command
starts with the same letter. "f" stands for "finish", use "fr" for "frame".
- Hitting <CR> will repeat the previous one. When doing another command, this
is reset (because it's not clear what you want to repeat).
- When you want to use the Ex command with the same name, prepend a colon:
":cont", ":next", ":finish" (or shorter).
*vim9-debug*
When debugging a compiled :def function, "step" will stop before every
executed line, not every single instruction. Thus it works mostly like a not
compiled function. Access to local variables is limited you can use: >
echo varname
But not much else.
When executing a command that is not a specific bytecode instruction but
executed like a normal Ex command, "step" will stop once in the compiled
context, where local variables can be inspected, and once just before
executing the command.

The backtrace shows the hierarchy of function calls, e.g.:
>bt ~
3 function One[3] ~
2 Two[3] ~
->1 Three[3] ~
0 Four ~
line 1: let four = 4 ~

The "->" points to the current frame. Use "up", "down" and "frame N" to
select another frame.

In the current frame you can evaluate the local function variables. There is
no way to see the command at the current line yet.


DEFINING BREAKPOINTS
*:breaka* *:breakadd*
:breaka[dd] func [lnum] {name}
Set a breakpoint in a function. Example: >
:breakadd func Explore
< Doesn't check for a valid function name, thus the breakpoint
can be set before the function is defined.

:breaka[dd] file [lnum] {name}
Set a breakpoint in a sourced file. Example: >
:breakadd file 43 .vimrc

:breaka[dd] here
Set a breakpoint in the current line of the current file.
Like doing: >
:breakadd file <cursor-line> <current-file>
< Note that this only works for commands that are executed when
sourcing the file, not for a function defined in that file.

:breaka[dd] expr {expression}
Sets a breakpoint, that will break whenever the {expression}
evaluates to a different value. Example: >
:breakadd expr g:lnum
< Will break, whenever the global variable lnum changes.

Errors in evaluation are suppressed, you can use the name of a
variable that does not exist yet. This also means you will
not notice anything if the expression has a mistake.

Note if you watch a |script-variable| this will break
when switching scripts, since the script variable is only
valid in the script where it has been defined and if that
script is called from several other scripts, this will stop
whenever that particular variable will become visible or
inaccessible again.

The [lnum] is the line number of the breakpoint. Vim will stop at or after
this line. When omitted line 1 is used.

*:debug-name*
{name} is a pattern that is matched with the file or function name. The
pattern is like what is used for autocommands. There must be a full match (as
if the pattern starts with "^" and ends in "$"). A "*" matches any sequence
of characters. 'ignorecase' is not used, but "\c" can be used in the pattern
to ignore case |/\c|. Don't include the () for the function name!

The match for sourced scripts is done against the full file name. If no path
is specified the current directory is used. Examples: >
breakadd file explorer.vim
matches "explorer.vim" in the current directory. >
breakadd file *explorer.vim
matches ".../plugin/explorer.vim", ".../plugin/iexplorer.vim", etc. >
breakadd file */explorer.vim
matches ".../plugin/explorer.vim" and "explorer.vim" in any other directory.

The match for functions is done against the name as it's shown in the output
of ":function". However, for local functions the script-specific prefix such
as "<SNR>99_" is ignored to make it easier to match script-local functions
without knowing the ID of the script.

Note that functions are first loaded and later executed. When they are loaded
the "file" breakpoints are checked, when they are executed the "func"
breakpoints.


DELETING BREAKPOINTS
*:breakd* *:breakdel* *E161*
:breakd[el] {nr}
Delete breakpoint {nr}. Use |:breaklist| to see the number of
each breakpoint.

:breakd[el] *
Delete all breakpoints.

:breakd[el] func [lnum] {name}
Delete a breakpoint in a function.

:breakd[el] file [lnum] {name}
Delete a breakpoint in a sourced file.

:breakd[el] here
Delete a breakpoint at the current line of the current file.

When [lnum] is omitted, the first breakpoint in the function or file is
deleted.
The {name} must be exactly the same as what was typed for the ":breakadd"
command. "explorer", "*explorer.vim" and "*explorer*" are different.


LISTING BREAKPOINTS
*:breakl* *:breaklist*
:breakl[ist]
List all breakpoints.


OBSCURE

*:debugg* *:debuggreedy*
:debugg[reedy]
Read debug mode commands from the normal input stream, instead
of getting them directly from the user. Only useful for test
scripts. Example: >
echo 'q^Mq' | vim -e -s -c debuggreedy -c 'breakadd file script.vim' -S script.vim

:0debugg[reedy]
Undo ":debuggreedy": get debug mode commands directly from the
user, don't use typeahead for debug commands.

 

posted @ 2022-01-02 00:26  箫笛  阅读(246)  评论(0)    收藏  举报