Creando un tmLanguage para Sublime (syntax definition)

  4 mins read

En este pequeño manual vamos a aprender a crear un coloreado de sintaxis para Sublime Text 2, un editor de texto multiplataforma que se ha convertido en algo más que necesario en mi día a día.

Instalando lo necesario

Asumiendo que tenemos Sublime Text instalado, necesitamos instalar el paquete de desarrollo de plugins, se llama AAAPackageDev. Para instalar este paquete os recomiendo que antes instaleis (si no lo tenéis ya) el Package Control, un plugin maestro que instala el resto de plugins, lo podeis instalar fácilmente haciendo clic en el menu “view > Show console” y copiando en la linea de comandos el script que aparece en su página oficial. Acordaos de reiniciar Sublime. Una vez que tengamos este paquete instalado presionamos CMD + SHIFT + P (CTRL + SHIFT + P en windows), este atajo equivale a la opción de menú “Package control”, tecleamos “Install” en la ventana emergente y seleccionamos la opción “Package Control: Install Package”, una vez hecho esto seleccionamos el paquete “AAAPackageDev” de la lista de paquetes.

Comenzando a desarrollar una nueva definición de lenguaje

También conocidas como “tmLanguage”, “Syntax definition”, etc… Hacemos clic en “Tools > Packages > Package development > New Syntax definition”. Veremos que aparece algo parecido a esto:

{ "name": "Syntax Name",
  "scopeName": "source.syntax_name",
  "fileTypes": [""],
  "patterns": [
  ],
  "uuid": "c4427f1b-df2e-4a4e-9891-d6b8bc9beb18"
}

Aquí una pequeña explicación de dichos parámetros:

  • Name: Nombre de esta definición, podemos usar cualquier nombre.
  • scopeName: Categoria y nombre interno de la definición, para lenguajes de programación usaremos “source.nombre_sintaxis” y para lenguajes de marcado usaremos “text.nombre_sintaxis”.
  • fileTypes: Las extensiones de ficheros a las cuales afecta.
  • uuid: Id único, no lo tocaremos.
  • patterns: lista de expresiones regulares que haran matching con el texto y coloreará nuestra sintaxis.

Esta parte es fácil de “rellenar”, ahora pasaremos al matching de texto.

Detectando el texto en una syntax definition

Para ello usaremos expresiones regulares, si no sabemos os recomiendo la lectura de esta serie de artículos antes de seguir. Un dato importante y que tenemos que tener en cuenta es que estas expresiones que vamos a definir se ejecutan para cada linea del texto. Ejemplo de expresión:

"patterns": [
  	{
      "comment" : "Main regex for language markup",
  		"match" : "^\s*"(.*)"\s*(=)\s*"(.*)"\s*;",
  		"captures": {
      		"1": { "name": "string.strings" },
      		"3": { "name": "string.strings" }
   		}
  	}

La propiedad comment es opcional, me gusta ponerlos para dejar estas expresiones lo más documentadas que pueda.
El “Match” es la expresión regular en sí, podemos hacer uso del número de grupos que queramos, en esta ocasión defino 3 aunque más adelante veremos que solo uso 2.
Captures, por cada grupo que hemos capturado anteriormente definimos con la key “name” que es este texto capturado, de esta forma Sublime colorea la sintaxis. No hace falta decirle colores puesto que esto no tendría sentido ya que se pueden crear temas para Sublime y decirle por ejemplo que todas las variables sean rojas, o azules pero eso es a gusto del usuario, por eso nosotros solo decimos que es una variable, una función, strings, números, etc… En este caso esta expresión regular la uso dentro de un plugin que he creado para colorear ficheros .string de objc así que definimos que ambos grupos son “strings”.

{
      "comment" : "in-line comment with #",
  		"match" : "^(#.*)",
  		"captures": {
      		"1": { "name": "comment.strings" }
   		}
  	}

En este ejemplo vemos que este grupo capturado pertenece a un comentario de código más concretamente la regex hace matching a las lineas que empiezan por #, fijaros como en la key “name” le ponemos “comment.”. Y ahora algo un poco más complicado, imaginaros que queremos capturar un comentario multilinea, antes hemos dicho que por cada linea del fichero abierto se ejecuta una regex, pero, entonces como podemos capturar un comentario de este tipo:

/**
* comentario
*/

Es fácil gracias al uso de los begin, beginCaptures, end, endCaptures:

{
      "comment" : "multi-line comments",
      "begin" : "^(\s*/\*.*)$",
      "beginCaptures": {
        "1": { "name": "comment.strings" }
      },
      "patterns": [
        { "include": "$self" },
        {  
          "name": "comment.strings",
          "match": "."
        }
      ],
      "end" : "^(\s*\*/\s*)$",
      "endCaptures": {
        "1": { "name": "comment.strings" }
      }
    }

BeginCaptures son los grupos capturados de “begin” y lo mismo ocurre con end y endCaptures. Solo tenemos que decir donde empieza lo que queremos capturar, es decir, la primera expresión regular captura el comienzo del comentario “/* ….”, uso el beginCaptures para decir que esta parte es un comentario.
Usamos el grupo patterns, para definir el contenido de lo que capturamos, en conjunto con el “include” : “$self” que lo usamos para decirle que lo que tiene que capturar es sobre el texto en el que estamos trabajando ahora y no sobre todo el documento.
El grupo end captura nuestro última linea y le decimos también que es parte del comentario con el “key” name “comment.”.

Probando nuestra definición

Para probar nuestra definición solo tenemos que seleccionar “Tools > Build System > json to tmLanguage” y darle a build (CMD +B en mac o CTRL + B en windows), esto nos generará un tmLanguage en el directorio donde tengamos instalado Sublime, acordaos de ponerlo en una carpeta como si fuera un paquete más, en Mac la ruta es: /Users//Library/Application Support/Sublime Text 2/Packages

También se puede ver la ruta desde “Preferences > Browse Packages”, una vez que tengamos todo guardado dentro de un paquete cada cambio que hagamos y construyamos refrescará automáticamente los ficheros con dicha extensión que tengamos abiertos, por lo que no es necesario reiniciar para ir probando cambios cuando estemos desarrollando un plugin.

Referencias y ejemplo completo

El ejemplo completo de este plugin que define la sintaxis de los .string de iOS / OSX lo tenéis colgado en GitHub.
Por último recordaos que tenéis más información en la propia página de documentación de Sublime y que si tenéis dudas me las podéis preguntar en Twitter o en la sección de comentarios de esta misma página.

Written by:

Christian Panadero Martinez

  • Pingback: sublime text 2 | cinco mundos()

  • ¡Hola! No consigo instalar el plugin y no es el primer plugin que instalo en Sublime Text. ¿Es necesario contar con una licencia especial (pagada) para acceder a package development?