Cómo crear extensiones para Visual Studio 2013 (vsix)

Andaba yo por ahí dando Soporte a uno de mis SaaS que tengo sobre Azure, cuando noté que era muy molesto que dado que el internet 4G que tengo me cambia en todo momento la IP, entonces siempre tenía que meterme al portal a agregar una nueva regla de firewall para poder acceder a administrar la SQL DB desde mi máquina local.

Entonces se me ocurrió escribir un script en powershell que hiciera esa tarea en batch, de manera de que ya me podría ahorrar mucho tiempo. Además me motivó el hecho de que ahora en VS2013 tenemos un excelente plugin que nos permite desarrollar sobre PowerShell directamente desde Visual Studio.

Pues bien, acabé de hacer mi script, e iba a pasar a poner en la documentación la fecha en la que fue creado. Pero oh sorpresa cuando noté que no tenía ni idea de cuál era la fecha en la que estábamos. Así que miré en el teléfono y vi que no podía hacer copy paste de esa fecha.

Y bueno, abrí notepad para presionar F5, pues esto inserta la fecha y hora actual en el editor y podría copiar y pegarla en Visual Studio. Pero sucede que reemplacé Notepad por Notepad++ y este último tampoco tiene esa funcionalidad.

Así que para nunca tener que volver a pasar por esta inmensa agonía, decidí escribir mi propia macro para Visual Studio 2013, que insertara la fecha y hora… pero; momento, las macros ya no están en Visual Studio 2013. Así que a hacer una extensión se dijo.

Afortunadamente hoy a diferencia de cuando yo hacía las extensiones para un lenguaje de programación que estaba creando llamado APL.NET por allá en 2005, crear extensiones para VS es muy sencillo. Y obviamente, se puede a punta de código administrado.

Basta descargar el SDK de Visual Studio 2013 que es de apenas unos cientos de megas. Después de esto ya en el mismísimo Visual Studio 2013 tendremos unas nuevas plantillas de proyecto para extensibilidad:

image

Las opciones son enormes. Pero para comenzar, crearemos un Visual Studio Package. Con esto será suficiente para crear la extensión que inserta un timestamp en el editor de código de Visual Studio 2013.

Esto nos lleva a un Wizard donde primero escogemos el lenguaje y firmamos el assembly con una llave propia o una autogenerada. La autogenerada funciona bien.

image

Luego agregamos la información básica de nuestra extensión:

image

Ahora escogemos las funcionalidades ofrecidas por nuestra extensión. Como solo quiero insertar la fecha y la hora, un comando de menú basta

image

Asignamos un nombre programático y uno descriptivo para nuestro comando. El nombre descriptivo es el que aparecerá en el menú Tools de Visual Studio 2013 para que al hacerle clic, la fecha y hora se inserte en nuestro editor:

image

El soporte a testing está incluido si lo deseamos. Por ahora no lo incluiré y sencillamente daré Finish:

image

Obtenemos entonces una solución nueva con esta estructura:

image

El archivo que seleccioné es el core de nuestro comando y allí es donde lo vamos a implementar.

Si alguna vez escribieron macros para VS con VB, recordarán el famoso objeto DTE (Development Tool Environment). Este es el objeto que encapsula toda el modelo de objetos de automatización de Visual Studio. Así que recurriremos a él para poder intervenir en el editor de código.

El assembly que lo incluye (EnvDTE) ya viene referenciado por el wizard. Así que solo basta incluir el Namespace.

 using EnvDTE;

Ahora buscamos el método MenuItemCallback y borramos el código por defecto que incluye.

         private void MenuItemCallback(object sender, EventArgs e)
        {
            
        }

El código que escribamos dentro de este método será el que se ejecute cuando el usuario le hace clic al comando. Copiaré aquí todo el código con extensos comentarios para que observen como trabajé la extensión:

 private void MenuItemCallback(object sender, EventArgs e)
{
    //Obtenemos una referencia al objeto DTE



    DTE dte = GetService(typeof(DTE)) as DTE;
    //El objeto DTE tiene un documento activo y es aquel 
    //archivo de código sobre el que estamos
    //trabajando actualmente. Este documento activo tiene
    //varios objetos sobre los que podemos actuar. Aquí como
    //modificaremos el texto, hacemos referencia al contenido
    //de texto del documento activo:
    TextDocument objTextDoc = 
         dte.ActiveDocument.Object("TextDocument") 
         as TextDocument;
 
    //Este objeto de tipo TextDocument tiene un atributo 
    //llamado Selection que como su nombre lo indica, nos
    //permite acceder al texto seleccionado en el editor.
    //De esta manera nos permite cambiarlo. Si no hay texto

    //seleccionado, entonces nos retorna cadena vacía.
    //Qué pasaría si cambiamos el texto en este caso?
    //Correcto, se inserta un nuevo texto en la posición actual 
    //del cursor. Entonces sencillamente procedemos:
    objTextDoc.Selection.Text =
        String.Concat(DateTime.Now.ToShortDateString(),
        " - ",
    DateTime.Now.ToShortTimeString());
}

Y bien, apuesto que muchos de ustedes jamás pensaron que fuera tan fácil escribir una extensión para Visual Studio 2013.

Ahora, para probar la extensión, en Visual Studio siempre hemos tenido una gran característica que es la instancia experimental de Visual Studio. De manera que nuestras extensiones propias no vayan a dañar nuestra instalación en producción de Visual Studio. O sea que si ejecutamos este proyecto, se abre otro Visual Studio (experimental) y la extensión se ejecuta solo sobre este último (imagínense un “emulador” de VS). El debug se hace idéntico a el que se haría con cualquier tipo de aplicación convencional:

image

Y el resultado de hacer clic sobre el comando:

image

Ahora solo basta compilar ir a la carpeta bin por nuestro archivo .vsix, que es auto instalable en los sistemas con Visual Studio 2013:

image

Si le damos doble clic, nuestra extensión se instalará ahora sí en nuestra versión de producción de Visual Studio y ya no tendremos problema porque no sabemos en qué fecha estamos cuando vayamos a poner un timestamp! Smile

He abierto el código fuente de esta solución y lo puedes encontrar en mi cuenta de Github:

Por si fuera poco, si queremos compartir la extensión, la podemos subir gratuitamente a la Galería de Visual Studio donde miles de desarrolladores tendrán acceso a ella. El proceso es muy sencillo y permite además de subir la extensión ponerle tags para que por ejemplo cuando un desarrollador busque insert timestamp, obtenga resultados:

image

Es más, si desde dentro de Visual Studio el developer entra a Tools->Extensions and Updates, nuestra extensión también queda disponible:

image

Es una excelente forma de compartir con la comunidad!!!