Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Python

Cómo crear un complemento de Sublime Text 2

by
Difficulty:IntermediateLength:LongLanguages:

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

Sublime Text 2 es un editor de texto altamente personalizable que ha captado cada vez más la atención de los codificadores que buscan una herramienta potente, rápida y moderna. Hoy, vamos a recrear mi popular plugin Sublime que envía CSS a través de la API Tuts+ Prefixr para facilitar el CSS entre navegadores.

Cuando hayas terminado, tendrás una sólida comprensión de cómo se escribe el complemento Prefixr Sublime y estarás preparado para comenzar a escribir tus propios complementos para el editor.


Prefacio: Terminología y material de referencia

El modelo de extensión para Sublime Text 2 es bastante completo.

El modelo de extensión para Sublime Text 2 es bastante completo. Hay formas de cambiar el resaltado de sintaxis, el cromo real del editor y todos los menús. Además, es posible crear nuevos sistemas de compilación, autocompletas, definiciones de lenguaje, fragmentos, macros, enlaces de teclas, enlaces de mouse y complementos. Todos estos tipos diferentes de modificaciones se implementan a través de archivos que están organizados en paquetes.

Un paquete es una carpeta que está almacenada en su directorio de paquetes Packages . Puede acceder al directorio de paquetes haciendo clic en la entrada de menú Preferences > Browse Packages... También es posible agrupar un paquete en un único archivo creando un archivo zip y cambiando la extensión a .sublime-package. Hablaremos del embalaje un poco más adelante en este tutorial.

Sublime viene incluido con un buen número de paquetes diferentes. La mayoría de los paquetes incluidos son específicos del idioma. Estos contienen definiciones de lenguaje, autocompletas y sistemas de compilación. Además de los paquetes de idiomas, hay otros dos paquetes: Default y User. El
paquete Default contiene todos los enlaces de teclas estándar, definiciones de menú, configuraciones de archivos y un montón de complementos escritos en Python. El paquete User es especial, ya que siempre se carga por última vez. Esto permite a los usuarios sobrescribir los valores predeterminados al personalizar los archivos en su paquete User.

Durante el proceso de escribir un complemento, la referencia de Sublime Text 2 API será esencial.

Durante el proceso de escribir un complemento, la referencia de Sublime Text 2 API será esencial. Además, el paquete Default actúa como una buena referencia para descubrir cómo hacer las cosas y qué es posible. Gran parte de la funcionalidad del editor se expone mediante comandos. Cualquier operación que no sea escribir caracteres se realiza a través de comandos. Al ver Preferences > Key Bindings - Default, es posible encontrar un tesoro oculto de funcionalidad incorporada.

Ahora que la distinción entre un complemento y un paquete es clara, comencemos a escribir nuestro complemento.


Paso 1: crear un complemento

Sublime viene con una funcionalidad que genera un esqueleto de código Python necesario para escribir un plugin simple. Seleccione la entrada de menú Tools > New Plugin... y se abrirá un nuevo búfer con esta plantilla.

Aquí puede ver que los dos módulos Sublime Python se importan para permitir el uso de la API y se crea una nueva clase de comando. Antes de editar esto y comenzar a crear nuestro propio complemento, guardemos el archivo y activamos la funcionalidad incorporada.

Cuando guardemos el archivo vamos a crear un nuevo paquete para almacenarlo. Presione ctrl + s (Windows / Linux) o cmd + s (OS X) para guardar el archivo. El diálogo de guardar se abrirá en el paquete User. No guarde el archivo allí, sino que busque una carpeta y cree una nueva carpeta llamada Prefixr.

Ahora guarde el archivo dentro de la carpeta Prefixr como Prefixr.py. En realidad, no importa el nombre del archivo, solo que termina en .py. Sin embargo, por convención utilizaremos el nombre del complemento para el nombre del archivo.

Ahora que el plugin está guardado, probemoslo. Abra la consola Sublime presionando ctrl + `. Esta es una consola de Python que tiene acceso a la API. Ingrese el siguiente Python para probar el nuevo complemento:

Debería ver Hello World insertado en el comienzo del archivo de complemento. Asegúrese de deshacer este cambio antes de continuar.


Paso 2 - Tipos de comandos y nombres

Para complementos, Sublime proporciona tres tipos diferentes de comandos.

  • Los comandos de texto proporcionan acceso a los contenidos del archivo / buffer seleccionado a través de un objeto View
  • Los comandos de ventana proporcionan referencias a la ventana actual a través de un objeto Window
  • Los comandos de la aplicación no tienen una referencia a ninguna ventana o archivo / buffer específico y son más raramente utilizados

Como vamos a manipular el contenido de un archivo CSS / buffer con este complemento, vamos a utilizar la clase sublime_plugin.TextCommand como base de nuestro comando Prefixr personalizado. Esto nos lleva al tema de nombrar clases de comando.

En el esqueleto del complemento provisto por Sublime, notará la clase:

Cuando queríamos ejecutar el comando, ejecutamos el siguiente código en la consola:

Sublime tomará cualquier clase que extienda una de las clases sublime_plugin
(TextCommand, WindowCommand o ApplicationCommand), elimine el sufijo Command y luego convierta CamelCase en underscore_notation para el nombre del comando.

Por lo tanto, para crear un comando con el nombre prefixr, la clase debe ser PrefixrCommand.


Paso 3 - Seleccionar texto

Una de las características más útiles de Sublime es la capacidad de tener múltiples selecciones.

Ahora que tenemos nuestro plugin nombrado correctamente, podemos comenzar el proceso de capturar CSS del buffer actual y enviarlo a la API Prefixr. Una de las características más útiles de Sublime es la capacidad de tener múltiples selecciones. Mientras tomamos el texto seleccionado, debemos escribir nuestro complemento en el controlador no solo en la primera selección, sino en todas.

Dado que estamos escribiendo un comando de texto, tenemos acceso a la vista actual a través de self.view. El método sel() del objeto View devuelve un RegionSet iterable de las selecciones actuales. Comenzamos escaneando a través de estos para llaves. Si las llaves no están presentes, podemos expandir la selección a las llaves adyacentes para asegurar que todo el bloque esté prefijado. Si nuestra selección incluye o no llaves también será útil más adelante para saber si podemos ajustar el espacio en blanco y el formato en el resultado que obtenemos de la API Prefixr.

Este código reemplaza el contenido del método skeleton run().

Si no encontramos llaves, recorremos cada selección y ajustamos las selecciones al corsé de cierre más cercano. A continuación, utilizamos el comando integrado expand_selection con argumento to establecido en corchetes para garantizar que tengamos el contenido completo de cada bloque CSS seleccionado.

Si desea verificar su trabajo hasta el momento, compare la fuente con el archivo Prefixr-1.py en el archivo zip del código fuente.


Paso 4 - Hilos

Para evitar que una mala conexión interrumpa otros trabajos, debemos asegurarnos de que las llamadas a la API Prefixr se realicen en segundo plano.

En este punto, las selecciones se han expandido para captar el contenido completo de cada bloque de CSS. Ahora, debemos enviarlos a la API Prefixr. Esta es una solicitud HTTP simple, para la cual vamos a usar los módulos urllib y urllib2. Sin embargo, antes de comenzar a lanzar solicitudes web, debemos pensar cómo una solicitud web potencialmente retrasada podría afectar el rendimiento del editor. Si, por algún motivo, el usuario tiene una latencia alta o una conexión lenta, las solicitudes a la API de Prefixr podrían tardar unos segundos o más.

Para evitar que una mala conexión interrumpa otros trabajos, debemos asegurarnos de que las llamadas a la API Prefixr se realicen en segundo plano. Si no sabe nada sobre el uso de subprocesos, una explicación muy básica es que los subprocesos son una forma de que un programa programe múltiples conjuntos de código para que se ejecuten aparentemente al mismo tiempo. Es esencial en nuestro caso porque permite que el código que está enviando datos y esperando una respuesta de la API Prefixr impida que se congele el resto de la interfaz de usuario Sublime.


Paso 5 - Creando Hilos

Utilizaremos el módulo threading de Python para crear subprocesos. Para usar el módulo de subprocesamiento, creamos una nueva clase que amplía threading.Thread se llama PrefixrApiCall. Clases que amplían el threading.Thread. El subproceso incluye un método run() que contiene todo el código que se ejecutará en el subproceso.

Aquí usamos el método thread __init__() para establecer todos los valores que se necesitarán durante la solicitud web. El método run() contiene el código para configurar y ejecutar la solicitud HTTP para la API Prefixr. Como los hilos funcionan simultáneamente con otros códigos, no es posible devolver valores directamente. En cambio, configuramos self.result para el resultado de la llamada.

Como recién comenzamos a usar más módulos en nuestro complemento, debemos agregarlos a las declaraciones de importación en la parte superior del script.

Ahora que tenemos una clase de subprocesos para realizar llamadas HTTP, necesitamos crear un hilo para cada selección. Para hacer esto volvemos al método run() de nuestra clase PrefixrCommand y usamos el siguiente ciclo:

Hacemos un seguimiento de cada hilo que creamos y luego llamamos al método start() para comenzar cada uno.

Si desea verificar su trabajo hasta el momento, compare la fuente con el archivo Prefixr-2.py en el archivo zip del código fuente.


Paso 6 - Preparación para los resultados

Ahora que hemos comenzado las solicitudes de API de Prefixr reales, debemos completar algunos detalles antes de manejar las respuestas.

Primero, borramos todas las selecciones porque las modificamos antes. Más tarde los restableceremos a un estado razonable.

Además, comenzamos un nuevo objeto Edit. Esto agrupa operaciones para deshacer y rehacer. Especificamos que estamos creando un grupo para el comando prefixr.

Como paso final, llamamos a un método que vamos a escribir a continuación para gestionar el resultado de las solicitudes de la API.


Paso 7 - Manejo de hilos

En este punto, nuestros hilos se están ejecutando, o posiblemente incluso se han completado. A continuación, debemos implementar el método handle_threads() al que nos hemos referido. Este método recorrerá la lista de subprocesos y buscará los subprocesos que ya no se ejecutan.

Si un hilo todavía está vivo, lo agregamos a la lista de hilos para verificarlo más tarde. Si el resultado fue un error, lo ignoramos; sin embargo, para obtener buenos resultados llamamos a un nuevo método  replace() que escribiremos pronto.

Si hay algún hilo que aún esté activo, necesitamos verificarlo nuevamente en breve. Además, es una mejora de la interfaz de usuario agradable para proporcionar un indicador de actividad para mostrar que nuestro complemento todavía se está ejecutando.

La primera sección del código usa un valor entero simple almacenado en la variable i para mover un = ida y vuelta entre dos corchetes. La última parte es la más importante sin embargo. Esto le dice a Sublime que vuelva a ejecutar el método handle_threads(), con nuevos valores, en otros 100 milisegundos. Esto es como la función setTimeout() en JavaScript.

La palabra clave lambda es una función de Python que nos permite crear una nueva función anónima o sin nombre.

El método sublime.set_timeout() requiere una función o método y la cantidad de milisegundos hasta que se ejecute. Sin lambda podríamos decir que queríamos ejecutar handle_threads(), pero no podríamos especificar los parámetros.

Si todos los hilos se han completado, no necesitamos establecer otro tiempo de espera, sino que terminamos nuestro grupo de deshacer y actualizamos la interfaz de usuario para que el usuario sepa que todo está hecho.

Si desea verificar su trabajo hasta el momento, compare la fuente con el archivo Prefixr-3.py en el archivo zip del código fuente.


Paso 8 - Realización de reemplazos

Con nuestros hilos procesados, ahora solo necesitamos escribir el código que reemplaza el CSS original con el resultado de la API Prefixr. Como mencionamos anteriormente, vamos a escribir un método llamado replace().

Este método acepta una serie de parámetros, incluido el objeto Edit para deshacer, el hilo que tomó el resultado de la API de Prefixr, si la selección original incluyó llaves, y finalmente la compensación de selección.

El desplazamiento es necesario cuando se trata de selecciones múltiples. Cuando reemplazamos un bloque de CSS con el CSS prefijado, la longitud de ese bloque aumentará. El desplazamiento asegura que estamos reemplazando el contenido correcto para selecciones posteriores ya que el texto coloca todos los cambios en cada reemplazo.

El siguiente paso es preparar el resultado de la API Prefixr para que se incluya como CSS de reemplazo. Esto incluye la conversión de los finales de línea y la sangría para que coincida con el documento actual y la selección original.

Como paso final, configuramos la selección del usuario para que incluya el final de la última línea del nuevo CSS que insertamos, y luego devolvemos el desplazamiento ajustado para usarlo en cualquier otra selección.

Si desea verificar su trabajo hasta el momento, compare la fuente con el archivo Prefixr-4.py en el archivo zip del código fuente.


Paso 9 - Manipulación del espacio en blanco

Usamos dos métodos personalizados durante el proceso de reemplazo para preparar el nuevo CSS para el documento. Estos métodos toman el resultado de Prefixr y lo modifican para que coincida con el documento actual.

normalize_line_endings() toma la cadena y se asegura de que coincida con los finales de línea del archivo actual. Usamos la clase Settings de la API Sublime para obtener las terminaciones de línea apropiadas.

El método fix_whitespace() es un poco más complicado, pero realiza el mismo tipo de manipulación, solo para la sangría y el espacio en blanco en el bloque CSS. Esta manipulación solo funciona con un solo bloque de CSS, por lo que salimos si se incluyeron uno o más refuerzos en la selección original.

De lo contrario, comenzamos determinando el nivel de sangría del CSS original. Esto se hace buscando espacios en blanco al comienzo de la selección.

A continuación, recortamos los espacios en blanco del CSS prefijado y usamos la configuración de vista actual para sangrar el CSS recortado al nivel original utilizando pestañas o espacios dependiendo de la configuración actual del editor.

Terminamos el método utilizando el espacio inicial y el espacio blanco final para asegurarnos de que el nuevo CSS prefijado se ajuste exactamente en lugar del original.

Con el método fix_whitespace() usamos el módulo de expresión regular de Python, por lo que debemos agregarlo a la lista de importaciones en la parte superior del script.

Y con esto, hemos completado el proceso de escribir el comando prefixr. El siguiente paso es hacer que el comando sea fácil de ejecutar al proporcionar un atajo de teclado y una entrada de menú.


Paso 10 - Ataduras de teclas

La mayoría de las configuraciones y modificaciones que se pueden hacer a Sublime se realizan a través de archivos JSON, y esto es cierto para las asociaciones de teclas. Los enlaces de teclas generalmente son específicos del sistema operativo, lo que significa que se necesitarán crear tres archivos de enlaces clave para su complemento. Los archivos deben ser nombrados Default (Windows).sublime-keymap, Default (Linux).sublime-keymap y Default (OSX).sublime-keymap.

Los archivos .sublime-keymap contienen una matriz JSON que contiene objetos JSON para especificar las asociaciones de teclas. Los objetos JSON deben contener claves y una tecla de comando, y también pueden contener una clave args si el comando requiere argumentos. La parte más difícil de elegir un enlace de clave es asegurarse de que el enlace de clave no se haya utilizado todavía. Para ello, vaya a Preferences > Key Bindings – Default y busque la combinación de teclas que desea utilizar. Una vez que haya encontrado un enlace adecuadamente no utilizado, agréguelo a sus archivos .sublime-keymap .

Normalmente, las combinaciones de teclas de Linux y Windows son las mismas. La clave cmd en OS X se especifica mediante la cadena super en los archivos .sublime-keymap . Cuando se transfiere una vinculación de clave a través de sistemas operativos, es común que la tecla Ctrl en Windows y Linux se intercambie por super en OS X. Sin embargo, esto puede no ser siempre el movimiento más natural de la mano, así que si es posible intente y pruebe sus combinaciones de teclas en un teclado real.


Paso 11 - Entradas de menú

Una de las cosas más interesantes acerca de la extensión de Sublime es que es posible agregar elementos a la estructura del menú creando archivos .sublime-menu . Los archivos de menú deben tener nombres específicos para indicar a qué menú afectan:

  • Main.sublime-menu controla el menú principal del programa
  • Side Bar.sublime-menu controla el menú contextual en un archivo o carpeta en la barra lateral
  • Context.sublime-menu controla el menú contextual en un archivo que se está editando

Hay muchos otros archivos de menú que afectan a otros menús en toda la interfaz. Navegar por el paquete Default es la forma más fácil de aprender sobre todos estos.

Para Prefixr queremos agregar un elemento de menú al menú Edit y algunas entradas al menú Preferences para la configuración. El siguiente ejemplo es la estructura JSON para la entrada del menú Edit. He omitido las entradas para el menú de Preferences ya que son bastante detallados anidados unos niveles de profundidad.

La única pieza a tener en cuenta son las teclas de id. Al especificar el ID de una entrada de menú existente, es posible agregar una entrada sin redefinir la estructura existente. Si abre el archivo Main.sublime-menu del paquete Default y navega, puede determinar a qué id desea agregar su entrada.

En este punto, su paquete Prefixr debería verse casi idéntico a la versión oficial en GitHub.


Paso 12 - Distribuye tu paquete

Ahora que se ha tomado el tiempo de escribir un útil complemento Sublime, es hora de ponerse en la mano de otros usuarios.

Sublime admite la distribución de un archivo zip de un directorio de paquetes como una forma sencilla de compartir paquetes. Simplemente comprima la carpeta de su paquete y cambie la extensión a .sublime-package. Otros usuarios pueden ahora colocar esto en su directorio de Installed Packages y reiniciar Sublime para instalar el paquete.

Además de la fácil disponibilidad para muchos usuarios, tener su paquete disponible a través de Package Control garantiza que los usuarios se actualicen automáticamente a sus últimas actualizaciones.

Si bien esto ciertamente puede funcionar, también hay un administrador de paquetes para Sublime llamado Package Control que admite una lista maestra de paquetes y actualizaciones automáticas. Para que su paquete se agregue al canal predeterminado, simplemente hágalo en GitHub o BitBucket y luego bifurque el archivo del canal (en GitHub o BitBucket), agregue su repositorio y envíe una solicitud de extracción. Una vez que se acepte la solicitud de extracción, su paquete estará disponible para miles de usuarios que utilizan Sublime. Además de la fácil disponibilidad para muchos usuarios, tener su paquete disponible a través de Package Control garantiza que los usuarios se actualicen automáticamente a sus últimas actualizaciones.

Si no desea alojar en GitHub o BitBucket, existe un sistema de canal / repositorio JSON personalizado que se puede usar para alojar en cualquier lugar, al mismo tiempo que proporciona el paquete a todos los usuarios. También proporciona una funcionalidad avanzada como la especificación de la disponibilidad de paquetes por SO. Vea la página PackageControl para más detalles.


¡Vaya a escribir algunos complementos!

Ahora que hemos cubierto los pasos para escribir un plugin Sublime, ¡es hora de que te sumerjas! La comunidad de plugins Sublime está creando y publicando nuevas funcionalidades casi todos los días. Con cada lanzamiento, Sublime se vuelve más y más poderoso y versátil. El Sublime Text Forum es un gran lugar para obtener ayuda y hablar con otros sobre lo que estás construyendo.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.