Validating Breakpoints (Managed Package Framework)
A breakpoint is a marker that indicates that program execution should stop at a particular point while running the program in a debugger. A user can place a breakpoint on any line in the source file since the editor has no knowledge of what constitutes a valid location for a breakpoint. When the debugger is launched, all of the placed breakpoints — called pending breakpoints — are bound to the appropriate location in the running program. In the act of binding these breakpoints, the breakpoints are validated to ensure they can actually appear at the specified location in the source code. For example, if a breakpoint is placed on a comment, the breakpoint is not considered valid because there is no code at that location in the source code and the debugger disables that breakpoint.
Since a language service has a fairly intimate knowledge of the source code being displayed, it can readily determine what constitutes a valid breakpoint location and therefore provide immediate feedback when a user puts a breakpoint on an inappropriate line.
The managed package framework (MPF) language service classes do not provide direct support for validating breakpoint locations. However, if you override one method in the LanguageService class, you can return a span specifying a valid location for a breakpoint. The breakpoint location is still validated when the debugger is launched but the user now receives immediate feedback without waiting for the debugger to load.
Implementing Support for Validating Breakpoints
All that is needed to enable support for validating breakpoints is to implement the ValidateBreakpointLocation method in the LanguageService class.
The ValidateBreakpointLocation method is given the position the breakpoint was placed on and it is up to your implementation to decide if that location can contain a breakpoint. You indicate this by returning a span that identifies the extent of the code on the line the breakpoint can be associated with.
In addition, a return value of S_OK indicates the breakpoint location is valid. A return value of S_FALSE indicates the breakpoint location is not valid. The returned span is highlighted along with the breakpoint, indicating the statement for which that the breakpoint is valid.
If S_FALSE is returned, a message appears in the status bar indicating the location is not valid for a breakpoint.
What constitutes a valid location for a breakpoint is dependent on your language and is entirely up to you.
Example
This brief example shows an implementation of the ValidateBreakpointLocation method in the LanguageService class that calls the parser to obtain the span of code (if any) at the specified location.
Note that the GetCodeSpan method on the MyAuthoringSink object is a custom method and was added to support this example.
using Microsoft VisualStudio;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;
namespace MyLanguagePackage
{
class MyLanguageService : LanguageService
{
public override int ValidateBreakpointLocation(IVsTextBuffer buffer,
int line,
int col,
TextSpan[] pCodeSpan)
{
int retval = VSConstants.E_NOTIMPL;
if (pCodeSpan != null)
{
// Initialize span to current line by default.
pCodeSpan[0].iStartLine = line;
pCodeSpan[0].iStartIndex = col;
pCodeSpan[0].iEndLine = line;
pCodeSpan[0].iEndIndex = col;
}
if (buffer != null)
{
IVsTextLines textLines = buffer as IVsTextLines;
if (textLines != null)
{
Source src = this.GetSource(textLines);
if (src != null)
{
TokenInfo tokenInfo = new TokenInfo();
string text = src.GetText();
ParseRequest req = CreateParseRequest(src,
line,
col,
tokenInfo,
text,
src.GetFilePath(),
ParseReason.CodeSpan,
null);
req.Scope = this.ParseSource(req);
MyAuthoringSink sink = req.Sink as MyAuthoringSink;
TextSpan span = new TextSpan();
// Assume line is invalid.
retval = VSConstants.S_FALSE;
if (sink.GetCodeSpan(out span))
{
pCodeSpan[0] = span;
retval = VSConstants.S_OK;
}
}
}
}
return retval;
}
}
}