web-dev-qa-db-fra.com

Ouvrir un fichier dans Visual Studio à un numéro de ligne spécifique

J'ai un utilitaire (grep) qui me donne une liste de noms de fichiers et un numéro de ligne. Après avoir déterminé que devenv est le bon programme pour ouvrir un fichier, j'aimerais m'assurer qu'il est ouvert au numéro de ligne indiqué. Dans Emacs, ce serait:

emacs +140 filename.c

Je n'ai rien trouvé de tel pour Visual Studio (devenv). Le plus proche que j'ai trouvé est:

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

Cependant, cela crée une instance distincte de devenv pour chacun de ces fichiers. Je préférerais que quelque chose utilise une instance existante.

Ces variations réutilisent un devenv existant, mais ne vont pas à la ligne indiquée:

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

Je pensais que plusieurs arguments "/ Command" pourraient suffire, mais je n’ai probablement pas le bon argument, car j’obtiens des erreurs ou aucune réponse (autre que l’ouverture d’un devenv vide).

Je pourrais écrire une macro spéciale pour devenv, mais j’aimerais que cet utilitaire soit utilisé par d’autres qui n’ont pas cette macro. Et je ne sais pas comment invoquer cette macro avec l'option "/ Command".

Des idées?


Eh bien, il ne semble pas qu’il existe un moyen de faire cela comme je le voulais. Comme il semble qu'il me faudra du code dédié pour démarrer Visual Studio, j'ai décidé d'utiliser EnvDTE comme indiqué ci-dessous. J'espère que cela aidera quelqu'un d'autre.

#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;
}
52
Harold Bamford

Je ne peux pas trouver un moyen de faire cela avec des options en ligne de commande. Il semble que vous deviez écrire une macro pour cela. Soi-disant, vous pouvez les invoquer comme ça.

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

Donc, vous pouvez probablement créer une macro qui prend un nom de fichier et un numéro de ligne, puis ouvre le fichier et saute au bon endroit. Mais, je ne sais pas si vous pouvez spécifier un indicateur de même instance quelque part ou non.

0
EndangeredMassa

Avec VS2008 SP1 , vous pouvez utiliser la ligne de commande suivante pour ouvrir un fichier sur une ligne spécifique d'une instance existante:

devenv /edit FILE_PATH /command "edit.goto FILE_LINE"

La source

29
Fouré Olivier

En développant la question et la réponse de Harold, j'ai adapté la solution C++ (que j'ai d'abord adoptée) au C #. C'est beaucoup plus simple (c'est mon premier programme C #!). Il suffit de créer un projet, d'ajouter des références à "envDTE" et "envDTE80" et de supprimer le code suivant:

using System;
using System.Collections.Generic;
using System.Text;

namespace openStudioFileLine
{
    class Program    
    {
        [STAThread]
        static void Main(string[] args)     
        {
            try          
            {
                String filename = args[0];
                int fileline;
                int.TryParse(args[1], out fileline);
                EnvDTE80.DTE2 dte2;
                dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
                dte2.MainWindow.Activate();
                EnvDTE.Window w = dte2.ItemOperations.OpenFile(filename, EnvDTE.Constants.vsViewKindTextView);
                ((EnvDTE.TextSelection)dte2.ActiveDocument.Selection).GotoLine(fileline, true);
            }
            catch (Exception e)          
            {          
                Console.Write(e.Message);      
            }
        }
    }
}

On appelle alors simplement openStudioFileLine path_to_file numberOfLine.

J'espère que cela peut aider!

26
reder

Basé sur reder answer j'ai publié un référentiel avec source , voici binaire (.net2.0)

J'ajoute également un support pour plusieurs versions de VS

usage: <version> <file path> <line number> 

Visual Studio version                 value 
VisualStudio 2002                     2 
VisualStudio 2003                     3 
VisualStudio 2005                     5 
VisualStudio 2008                     8 
VisualStudio 2010                    10 
VisualStudio 2012                    12 
VisualStudio 2013                    13 

Exemple utilisant de GrepWin:

VisualStudioFileOpenTool.exe 12 %path% %line%
13
diimdeep

Assez vieux fil, mais ça m'a permis de commencer alors voici un autre exemple. Cette fonction AutoHotkey ouvre un fichier et place le curseur sur une ligne et une colonne particulières.

; http://msdn.Microsoft.com/en-us/library/envdte.textselection.aspx
; http://msdn.Microsoft.com/en-us/library/envdte.textselection.movetodisplaycolumn.aspx
VST_Goto(Filename, Row:=1, Col:=1) {
    DTE := ComObjActive("VisualStudio.DTE.12.0")
    DTE.ExecuteCommand("File.OpenFile", Filename)
    DTE.ActiveDocument.Selection.MoveToDisplayColumn(Row, Col)
}

Appeler avec:

VST_Goto("C:\Palabra\.NET\Addin\EscDoc\EscDoc.cs", 328, 40)

Vous pouvez le traduire pratiquement ligne par ligne en VBScript ou JScript.

3
Wade Hatler

Voici la variante VBS de la solution de Harold: lien vers le script .vbs .

open-in-msvs.vbs full-path-to-file line column

Windows prend en charge VBScript en mode natif - pas besoin de compilation ni d’interpréteur supplémentaire.

3
Evgeny Panasyuk

Voici la variante Python de la solution de Harold:

import sys
import win32com.client

filename = sys.argv[1]
line = int(sys.argv[2])
column = int(sys.argv[3])

dte = win32com.client.GetActiveObject("VisualStudio.DTE")

dte.MainWindow.Activate
dte.ItemOperations.OpenFile(filename)
dte.ActiveDocument.Selection.MoveToLineAndOffset(line, column+1)

Il montre comment aller à la ligne spécifiée + colonne.

2
Evgeny Panasyuk

Pour référence, voici ENVDE écrit en C # (utilisant O2 Platform à l'intérieur de VisualStudio pour obtenir une référence à l'objet DTE en direct)

var visualStudio = new API_VisualStudio_2010();

var vsDTE = visualStudio.VsAddIn.VS_Dte;
//var document = (Document)vsDTE.ActiveDocument;
//var window =  (Window)document.Windows.first();           
var textSelection  = (TextSelection)vsDTE.ActiveDocument.Selection;
var selectedLine = 1;
20.loop(100,()=>{
                    textSelection.GotoLine(selectedLine++);
                    textSelection.SelectLine();
                });
return textSelection;

Ce code fait une petite animation où 20 lignes sont sélectionnées (avec un intervalle de 100ms)

1
Dinis Cruz

La ligne de commande wingrep correcte syntax pour forcer un new instance et passer à un numéro de ligne est la suivante: 

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" $F /command "edit.goto $L"

Remplacez le studio version number par la version appropriée pour votre configuration.

1
Richard Mills

L’utilisation de cette commande me convient tant que Visual Studio n’est PAS déjà ouvert. "C:\Programmes (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe"/edit "ABSOLUTEFILEPATH_FILENAME. CPP "/ command" Edit.GoTo 164 "

Si c'est déjà ouvert, alors parfois ça marche et va à la bonne ligne, mais alors ça cesse de fonctionner et je n'ai jamais compris pourquoi. On dirait que Microsoft est au courant du problème, mais a déclaré qu'il ne le "réparerait" pas, à moins que davantage de personnes ne se plaignent. Donc, si le problème persiste, je vous conseillerais de commenter ici: https://connect.Microsoft.com/VisualStudio/Feedback/Details/1128717

0
Craigw1701

Ces dépendances C # sur les références de projet sont totalement inutiles. En effet, une grande partie du code est trop verbeuse. Tout ce dont vous avez besoin est ceci.

using System.Reflection;
using System.Runtime.InteropServices;

private static void OpenFileAtLine(string file, int line) {
    object vs = Marshal.GetActiveObject("VisualStudio.DTE");
    object ops = vs.GetType().InvokeMember("ItemOperations", BindingFlags.GetProperty, null, vs, null);
    object window = ops.GetType().InvokeMember("OpenFile", BindingFlags.InvokeMethod, null, ops, new object[] { file });
    object selection = window.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, window, null);
    selection.GetType().InvokeMember("GotoLine", BindingFlags.InvokeMethod, null, selection, new object[] { line, true });
}

Simples hein?

0

J'étais sur le point de poser cette question parce que lorsque vous obtenez "l'écran jaune de la mort" lors du débogage d'une application Web, vous souhaitez accéder rapidement au fichier et à la ligne qu'il vous donne dans la pile, par exemple:

[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

Dites que je veux aller à ServiceUserController.cs à la ligne 41. En général, j'ouvre Visual Studio et le fais manuellement, mais j'ai ensuite écrit un petit script Autohotkey qui le fait.

Pour l'ouvrir, vous devez sélectionner le nom de fichier et le numéro de ligne, par exemple. ServiceUserController.cs:41 et ensuite appuyez sur votre raccourci Alt + v. Voici le code pour cela:

$!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

Vous voudrez coller les "fonctions utilitaires" suivantes:

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
Tahir Hassan