Visual Studio - inserting multi-line expressions i

2019-06-18 02:39发布

While debugging in Visual Studio, how can I insert multi-line expressions into Watch Window, so that each line is not broken into a separate INVALID watch expression. This is really frustrating because I have many expressions spanning multiple lines that I need to watch. Note that both Pin to Source and Immediate Window do not work for tracking multiple values from many places in source code.

e.g.

PyFunc1(Py.kw("var1", var1),
        Py.kw("var2", var2))

gets broken to:

PyFunc1(Py.kw("var1", var1),

and

Py.kw("var2", var2))

2条回答
再贱就再见
2楼-- · 2019-06-18 03:19

Repro

I dont think this is "By-Design", its just unavailable "out-of-the-box".

I agree, it'd be better behaviour for multi-line calls to be added to the Watch Window using line terminators instead of new lines:

enter image description here


Research

I found this similar question with a few "workarounds" to choose from: Multi-Line Watch Window in Visual Studio 2010?

I also found this comment in the MSDN Forums by a MSFT Engineer:

I’m afraid that it is not supported, we often edit them one by one. Maybe you could submit this feature request: http://visualstudio.uservoice.com/forums/121579-visual-studio


Roll your own Visual Studio Add-In

So I had a go at it myself, this is by no means production code but it shows you how to do it:

(click image to enlarge)

enter image description here

namespace AddinMultiLineWatch
{
public class Connect : IDTExtensibility2, IDTCommandTarget
{
    //ADD THESE MEMBER VARIABLES
    //private DebuggerEvents _debuggerEvents = null;
    //private _dispDebuggerEvents_OnEnterBreakModeEventHandler DebuggerEvents_OnEnterBreakMode;
    private Window _watchWindow = null;
    private CommandEvents _objCommandEvents;
    private bool _isRecursive = false;
    public Connect()
    {
    }

    public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
    {
        _applicationObject = (DTE2)application;
        _addInInstance = (AddIn)addInInst;

        //SET THE MEMBER VARIABLES
        //_debuggerEvents = _applicationObject.Events.DebuggerEvents;
        //_debuggerEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(BreakHandler);
        //var watchWindow = _applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindWatch);
        _objCommandEvents = _applicationObject.Events.CommandEvents;
        _objCommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(BeforeExecute);

        if(connectMode == ext_ConnectMode.ext_cm_UISetup)
        {
            object []contextGUIDS = new object[] { };
            Commands2 commands = (Commands2)_applicationObject.Commands;
            string toolsMenuName = "Tools";

            Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];
ar:
            CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
            CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

            try
            {
                Command command = commands.AddNamedCommand2(_addInInstance, "AddinMultiLineWatch", "AddinMultiLineWatch", "Executes the command for AddinMultiLineWatch", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

                if((command != null) && (toolsPopup != null))
                {
                    command.AddControl(toolsPopup.CommandBar, 1);
                }
            }
            catch(System.ArgumentException)
            {
            }
        }
    }

    //ADD THIS METHOD TO INTERCEPT THE DEBUG.ADDWATCH COMMAND
    public void BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
    {
        EnvDTE.Command objCommand = default(EnvDTE.Command);
        try
        {
            objCommand = _applicationObject.Commands.Item(Guid, ID);
        }
        catch (Exception ex)
        {
        }

        if ((objCommand != null))
        {
            if (objCommand.Name == "Debug.AddWatch")
            {
                //if (_isRecursive) return;
                //_isRecursive = true;
                TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;
                //TODO make selection goto next semi-colon/Line Terminator...
                var selText = selection.Text;  

                if (string.IsNullOrEmpty(selText)) return;   
                //Only intercept multi-line Add Watch commands                    
                if (selText.Contains(Environment.NewLine))
                {
                  //THE BLACK MAGIC: make it fit in one line! lol
                  selText = selText.Replace(Environment.NewLine, string.Empty);              
                  //THIS CALL IS RECURSIVE, I'LL LEAVE IT TO THE READER AS AN EXERCISE TO SOLVE..
                _applicationObject.ExecuteCommand("Debug.AddWatch", selText);
               }
            }
        }
    }
  1. Create a New Project > Other Project Types > Extensibility > Visual Studio Add-In > name it AddinMultiLineWatch

  2. Go through the wizard

  3. Add the code above to the Connect.cs class - see my //UPPERCASE comments with what stuff to add.

  4. Put a break point on the line TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;

  5. Press F5 and a new instance of VS will launch > choose New Project > Console App > name it TestMultilineAddWatch

  6. In the program.cs of the Console App, specify a code call over 2 lines and put a break point on it, as shown in the screenshot, eg:

    Add(1,            //Breakpoint here and select both lines
            2);
    }
    
    static int Add(int i, int j)
    {
        return i + j;
    }
    
  7. F5 in the TestMultilineAddWatch solution and when the code control halts on the break point > select/highlight the two lines Add(1, \r\n 2) > right click > Add Watch

  8. Clicking Add Watch in the VS IDE debugging context menu causes the VS AddinMultiLineWatch solution to intercept the call and activate, halting on the break point.... where you will see the black magic of replacing multi lined code in to a single line sent to the Watch Window.

The Visual Studio EXEC command calling itself makes this method recursive, if you debug it, exiting out of the recursion manually you will see the results as per my screenshot.

Happy debugging!

查看更多
Fickle 薄情
3楼-- · 2019-06-18 03:40

You could do it using autohotkey and a custom key binding ( e.g. Alt+Shift+V)

!+v means Alt+Shift+v

The macro below: If in devenv.exe, and you press Alt+Shift+V, edit the clipboard contents, removing /r/n and replace them with nothing, then press Ctrl+V to paste

I tested this out cutting and pasting in a text document in visual studio.

#IfWinActive ahk_exe devenv.exe
!+v::
FixString = %clipboard%
StringReplace, FixString, FixString,`r`n,,A
Clipboard := FixString
Send, ^v
查看更多
登录 后发表回答