Откройте файл в Visual Studio по определенному номеру строки - PullRequest
52 голосов
/ 08 декабря 2008

У меня есть утилита (grep), которая дает мне список имен файлов и номеров строк. После того, как я определил, что devenv - правильная программа для открытия файла, я хочу убедиться, что он открывается по указанному номеру строки. В emacs это будет:

emacs +140 filename.c

Я не нашел ничего подобного для Visual Studio (devenv). Ближайшее, что я нашел, это:

devenv /Command "Edit.Goto 140" filename.c

Однако для каждого такого файла создается отдельный экземпляр devenv. Я предпочел бы иметь что-то, что использует существующий экземпляр.

Эти варианты повторно используют существующий devenv, но не переходят к указанной строке:

devenv /Command "Edit.Goto 140" /Edit filename.c
devenv /Command  /Edit filename.c "Edit.Goto 140"

Я думал, что это можно сделать с помощью нескольких аргументов "/ Command", но у меня, вероятно, нет нужного, потому что я либо получаю ошибки, либо вообще не получаю ответа (кроме открытия пустого devenv).

Я мог бы написать специальный макрос для devenv, но я бы хотел, чтобы эта утилита использовалась другими, у которых нет этого макроса. И я не совсем понимаю, как вызывать этот макрос с параметром "/ Command".

Есть идеи?


Ну, не похоже, что есть способ сделать это, как я хотел. Поскольку для запуска Visual Studio мне понадобится выделенный код, я решил использовать EnvDTE, как показано ниже. Надеюсь, это поможет кому-то еще.

#include "stdafx.h"

//-----------------------------------------------------------------------
// This code is blatently stolen from http://benbuck.com/archives/13
//
// This is from the blog of somebody called "BenBuck" for which there
// seems to be no information.
//-----------------------------------------------------------------------

// import EnvDTE
#pragma warning(disable : 4278)
#pragma warning(disable : 4146)
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
#pragma warning(default : 4146)
#pragma warning(default : 4278)

bool visual_studio_open_file(char const *filename, unsigned int line)
{
    HRESULT result;
    CLSID clsid;
    result = ::CLSIDFromProgID(L"VisualStudio.DTE", &clsid);
    if (FAILED(result))
        return false;

    CComPtr<IUnknown> punk;
    result = ::GetActiveObject(clsid, NULL, &punk);
    if (FAILED(result))
        return false;

    CComPtr<EnvDTE::_DTE> DTE;
    DTE = punk;

    CComPtr<EnvDTE::ItemOperations> item_ops;
    result = DTE->get_ItemOperations(&item_ops);
    if (FAILED(result))
        return false;

    CComBSTR bstrFileName(filename);
    CComBSTR bstrKind(EnvDTE::vsViewKindTextView);
    CComPtr<EnvDTE::Window> window;
    result = item_ops->OpenFile(bstrFileName, bstrKind, &window);
    if (FAILED(result))
        return false;

    CComPtr<EnvDTE::Document> doc;
    result = DTE->get_ActiveDocument(&doc);
    if (FAILED(result))
        return false;

    CComPtr<IDispatch> selection_dispatch;
    result = doc->get_Selection(&selection_dispatch);
    if (FAILED(result))
        return false;

    CComPtr<EnvDTE::TextSelection> selection;
    result = selection_dispatch->QueryInterface(&selection);
    if (FAILED(result))
        return false;

    result = selection->GotoLine(line, TRUE);
    if (FAILED(result))
        return false;

    return true;
}

Ответы [ 12 ]

0 голосов
/ 24 февраля 2014

Я собирался задать этот вопрос, потому что, когда вы получаете «желтый экран смерти» при отладке веб-приложения, вы хотите быстро перейти к файлу и строке, которые он вам дает в трассировке стека, например:

[ContractException: Precondition failed: session != null]
   System.Diagnostics.Contracts.__ContractsRuntime.TriggerFailure(ContractFailureKind kind, String msg, String userMessage, String conditionTxt, Exception inner) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   System.Diagnostics.Contracts.__ContractsRuntime.ReportFailure(ContractFailureKind kind, String msg, String conditionTxt, Exception inner) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   System.Diagnostics.Contracts.__ContractsRuntime.Requires(Boolean condition, String msg, String conditionTxt) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   IAS_UI.Web.IAS_Session..ctor(HttpSessionStateBase session) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Web\IAS_Session.cs:15
   IAS_UI.Controllers.ServiceUserController..ctor() in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\ServiceUserController.cs:41

Скажем, я хочу перейти к ServiceUserController.cs в строке 41. Обычно я открывал Visual Studio и делал это вручную, но затем я написал небольшой скрипт Autohotkey, который это делает.

Чтобы открыть его, выделите имя файла и номер строки, например, ServiceUserController.cs:41 и после этого нажмите ваш ярлык Alt + v. Вот код для этого:

$!v::
if (NOT ProcessExists("devenv.exe"))
{
    MsgBox, % "Visual Studio is not loaded"
}
else
{
    IfWinExist, Microsoft Visual Studio
    {
        ToolTip, Opening Visual Studio...
        c := GetClip()

        if (NOT c) {
            MsgBox, % "No text selected"
        }
        else 
        {
            WinActivate ; now activate visual studio
            Sleep, 50
            ; for now assume that there is only one instance of visual studio - handling of multiple instances comes in later

            arr := StringSplitF(c, ":")

            if (arr.MaxIndex() <> 2) {
                MsgBox, % "Text: '" . c . "' is invalid."
            }
            else {
                fileName := arr[1]
                lineNumber := arr[2]

                ; give focus to the "Find" box
                SendInput, ^d 

                ; delete the contents of the "Find" box
                SendInput, {Home}
                SendInput, +{End}
                SendInput, {Delete}

                ; input *** >of FILENAME *** into the "Find" box
                SendInput, >of{Space}
                SendInput, % fileName

                ; select the first entry in the drop down list
                SendInput, {Down}
                SendInput, {Enter}

                ; lineNumber := 12 remove later

                ; open the go to line dialog
                SendInput, ^g
                Sleep, 20

                ; send the file number and press enter
                SendInput, % lineNumber
                SendInput {Enter}
            }
        }    
        ToolTip
    }
}
return

Перед этим вам нужно вставить следующие «служебные функции»:

GetClip()
{
    ClipSaved := ClipboardAll
    Clipboard=
    Sleep, 30
    Send ^c
    ClipWait, 2
    Sleep, 30
    Gc := Clipboard
    Clipboard := ClipSaved
    ClipSaved=

    return Gc
}

ProcessExists(procName)
{
    Process, Exist, %procName%

    return (ErrorLevel != 0)
}

StringSplitF(str, delimeters)
{
    Arr := Object()

    Loop, parse, str, %delimeters%,
    {
        Arr.Insert(A_LoopField)
    }

    return Arr
}
0 голосов
/ 08 декабря 2008

Я не могу найти способ сделать это с прямыми параметрами командной строки. Похоже, вам придется написать макрос для него. Возможно, вы можете вызывать их так.

devenv /command "Macros.MyMacros.Module1.OpenFavoriteFiles"

Итак, вы, вероятно, можете создать макрос, который принимает имя файла и номер строки, затем открывает файл и переходит в нужное место. Но я не знаю, где можно указать флаг того же экземпляра или нет.

...