Está en la página 1de 11

Creando un Syntax Highlighter usando un RichTextBox

mar 22, 2010 en Entorno Visual por Un syntax highlighter o resaltador de sintaxis es simplemente un programa que resalta texto al igual como lo hacen tus IDEs de desarrollo para tus lenguajes favoritos. En este artculo te voy a ensear un mtodo muy simple para hacer el tuyo propio usando el componente RichTextBox de Visual Studio.

Un syntax highlighter completo es bastante complejo, ya que puede resaltar varios lenguajes de programacin que tienen muchas variaciones entre si. La idea de este artculo no es ensearte todo lo necesario para crear un syntax highlighter completo sino mostarte lo indispensable para que comiences con el pie derecho.

El producto final
En el fondo lo que vamos a hacer es convertir un editor de texto de tipo RichTextBox para que el texto que tiene dentro resalte las palabras claves y cadenas de texto que escribamos en el.

Preparando el ambiente
Lo primero que tienes que hacer es crear una nueva aplicacin de Entorno Visual. En este caso puedes usar C++ o C# ya que voy a mostrar el cdigo en ambos lenguajes. Luego a tu formulario agrgale un componente de tipo RichTextBox.

Configura el RichTextBox con las siguientes opciones: Propiedad Valor Descripcin Para que mientras escribamos se pueda usar la tecla TAB en lugar de que con ella se pase al siguiente componente en el formulario. Voy a desactivar esta opcin para que no se mezcle con la forma de resaltar cdigo. Esta opcin simplemente la uso para que ocupe toda la pantalla. Utilizo esta fuente para que se vea como cdigo y no como texto normal.

AcceptsTab True DetectUrls False Dock Fill Courier Font-name New

El RichTextBox
Antes de continuar es importante que entiendas como funciona el RichTexBox. Este componente funciona de forma muy parecida a un TextBox normal cuando estn en modo multilnea. La gran diferencia es que el RichTextBox guarda no solo la informacin del texto sino tambin la informacin del texto con formato. Por ejemplo si yo escribo la palabra "ABC" de color rojo el RichTextBox guarda dos cadenas: La primera es simplemente la palabra "ABC" y la segunda es algo as "{rtf1\red255}{val\ ABC}" que indica que esta palabra es roja. La primera es la propiedad Text y la segunda es la propiedad RTF (Rich Text Format). Para hacer un syntax highlighter lo que tenemos que hacer es generar el rtf correspondiente para cada una de las palabras claves que encontramos.

Evento Text Changed


Cada vez que el texto cambie, tenemos que volver a darle formato al texto. Es por esta razn que todo el cdigo necesario lo vamos a programar en el evento Text Changed del RichTextBox. Lo que tenemos que hacer en este evento es ir seleccionando porciones de texto y cambindole valores como color, fuente, etc. Podemos seleccionar todo el texto usando el comando SelectAll o porciones de texto usando el atributo SelectionStart y SelectionLength que marcan el inicio y longitud del pedazo seleccionado. Una vez que seleccionamos un pedazo de texto, podemos aplicarle formato utilizando una serie de propiedades, pero la que usaremos en este ejemplo es simplemente SelectionColor que nos permitir cambiarle el color al texto seleccionado.

Seleccionando solo las palabras int


Nuestro primer ejemplo solamente seleccionar las palabras int y las marcar con azul. C++

C#
01 private void richTextBox1_TextChanged(object sender, EventArgs e) 02 { 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 } // Regresamos todo a su sitio richTextBox1.SelectionStart = selStart; richTextBox1.SelectionLength = selLength; } } while (posInt != -1); // Si se encontro aplicamos el formato correcto if (posInt != -1) { // Seleccionamos la palabra int (mide 3 caracteres) richTextBox1.SelectionStart = posInt; richTextBox1.SelectionLength = 3; richTextBox1.SelectionColor = Color.Blue; // Buscamos todas la palabras int int posInt = -1; do { // Obtenemos la posicion de la palabra int posInt = richTextBox1.Text.IndexOf("int", posInt + 1); // Nos aseguramos de que todo el texto // este negro antes de ponerle color richTextBox1.SelectAll(); richTextBox1.SelectionColor = Color.Black; // Guardamos la selecciona actual para regresar // todo a su sitio cuando terminemos int selStart = richTextBox1.SelectionStart; int selLength = richTextBox1.SelectionLength;

Si ves detenidamente el cdigo puedes ver que lo primero que hacemos es guardar la informacin de la seleccin actual. Hacemos esto para poder reiniciar la seleccin al final y dejar al usuario donde se qued. Si quieres prueba quitando las ltimas lneas de esta funcin para que veas que sucede.

Adems, al inicio seleccionamos todo el texto y le colocamos el color negro. Aparentemente esto puede ser un error ya que no tiene sentido quitarle el formato a lo que ya habamos cambiado. Pero prueba quitando esas lneas y escribiendo texto al inicio, por ejemplo cambiando la primera palabra int que escribiste. Despus hacemos un bucle simple buscando cada palabra int a partir de la posicin anterior de la ltima palabra. Cada vez que la encontramos, la seleccionamos y le aplicamos el color azul. Por ltimo colocamos la seleccin en la posicin anterior. Si no hacemos esto, la seleccin se quedar en la ltima palabra int y no se podr escribir de forma continua.

Evitando el parpadeo
Si te has dado cuenta, cuando escribes bastante texto, el texto parpadea muchsimo. Esto se debe a la simple razn de que se est seleccionando texto en diferentes partes y para cada seleccin se est mostrando un cambio en la pantalla. Ahora, estos cambios ocurren muy rpido por lo que no los vemos sino que vemos un parpadeo. Hay muchas soluciones. Lo ideal sera detectar exactamente que ha cambiado y solamente modificar esto para lo cual puedes hacer uso de tablas hash, arboles, o cualquier otra estructura que te parezca conveniente. Ahora en la prctica esto es bastante difcil de implementar y no vale la pena el esfuerzo para un caso simple (si quieres desarrollar un IDE deberas considerarlo). Pero hay una solucin ms sencilla. Lo que no queremos es que se muestren las selecciones a medida que escribimos por lo que simplemente tenemos que desactivar el RichTextBox antes de comenzar y asegurarnos de activarlo otra vez al final. Si lo desactivamos perdemos el foco as que hay que habilitarlo y adems darle el foco. Coloco el cdigo anterior (no completo) pero con este cambio. C++ C#
01 private void richTextBox1_TextChanged(object sender, EventArgs e) 02 { 03 04 05 06 07 08 09 10 // Guardamos la selecciona actual para regresar // todo a su sitio cuando terminemos int selStart = richTextBox1.SelectionStart; int selLength = richTextBox1.SelectionLength; // Desactivamos el control richTextBox1.Enabled = false;

11 12 13 14 15 16 17 18 19 20 21 22 }

// Nos aseguramos de que todo el texto // este negro antes de ponerle color ................. // Regresamos todo a su sitio richTextBox1.SelectionStart = selStart; richTextBox1.SelectionLength = selLength; // Activamos el control richTextBox1.Enabled = true; richTextBox1.Focus();

Es realmente impresionante pero esas 3 lneas de cdigo que he puesto al inicio y al final hacen toda la diferencia.

Usando Regular Expressions


Un Regular Expression es una forma de realizar bsquedas utilizando formatos y expresiones. La idea de este artculo no es ensearte como usar regular expressions as que si quieres enterarte ms acerca de ellas te recomiendo que visites http://www.regularexpressions.info. En el cdigo completo voy a usar regular expressions para aplicar sintaxis a:

Palabras reservadas: int, float, double, char, new con color azul. Cadenas de texto: Todo lo que comience y termine con " de color rojo.

Para usar regular expressions en C++ y C# de Visual Studio tienes que aadir el namespace System::Text::RegularExpressions. El cdigo completo es el siguiente: C++ C#
01 private void richTextBox1_TextChanged(object sender, EventArgs e) 02 { 03 04 05 // Desactivamos el control richTextBox1.Enabled = false;

06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 }

// Guardamos la selecciona actual para regresar // todo a su sitio cuando terminemos int selStart = richTextBox1.SelectionStart; int selLength = richTextBox1.SelectionLength; // Nos aseguramos de que todo el texto // este negro antes de ponerle color richTextBox1.SelectAll(); richTextBox1.SelectionColor = Color.Black; // Declaramos las variables necesarias Regex reg; MatchCollection partes; // Buscamos todas la palabras reservadas reg = new Regex("(int|float|double|char|for) "); partes = reg.Matches(richTextBox1.Text); for (int i=0; i<partes.Count; i++) { richTextBox1.SelectionStart = partes[i].Index; richTextBox1.SelectionLength = partes[i].Length; richTextBox1.SelectionColor = Color.Blue; } // Buscamos todas las cadenas reg = new Regex("[\"][^\"]*[\"]"); partes = reg.Matches(richTextBox1.Text); for (int i=0; i<partes.Count; i++) { richTextBox1.SelectionStart = partes[i].Index; richTextBox1.SelectionLength = partes[i].Length; richTextBox1.SelectionColor = Color.Red; } // Regresamos todo a su sitio richTextBox1.SelectionStart = selStart; richTextBox1.SelectionLength = selLength; // Activamos el control richTextBox1.Enabled = true; richTextBox1.Focus();

Ten en cuenta, que estas expresiones regulares no son del todo correctas y no cumplen para todos los casos en lo que respecta a la sintaxis de C++ o C# pero las he mantenido simples para que el concepto quede claro.

Conclusin
Como puedes ver, crear un syntax highlighter es bastante simple. La complejidad est en la diversidad que quieras ofrecer. Si quieres que responda a varios lenguajes, que te permita resaltar cadenas, variables, palabras reservadas, comentarios, entre otros, se vuelve ms complicado. Lo bueno es que ya tienes la base y hacerlo crecer depende de t.

Siguiente artculoLos primeros 50 Artculos similares


Trabajando con Word en Visual Studio 2010 y C# TCSH Shell para Linux (Parte II) Abrir aplicaciones externas desde C++ jQuery, un nuevo tipo de librera Javascript Creando un TabSheet con jQuery

Artculo AnteriorAutomatizando tareas en Linux

Autor:

Comentarios (17)
Daniel abril 4, 2010 a las 4:47 pm exelente esto me va ha servir mucho muchas gracias ahora con una duda mo puedo mostrar los numeros de linea como en un richtextbox asi como se ve en el codigo que das de ejemplo.te lo agradeceria.muchas gracias Responder Alfredo Granda abril 5, 2010 a las 9:37 am

Daniel, Existen varias formas de colocar el nmero de lnea. Una es reemplazar todos los saltos de lnea (\n) por (\nX) donde X es el nmero de lnea. El problema con esto es que el nmero de lnea estara dentro del texto. Otra alternativa sera colocar un segundo componente que est al lado del cdigo y que solo contenga los nmeros de lnea. En el caso de nuestra pgina, cada lnea se encuentra ubicado dentro de un tag de HTML por lo que la numeracin es automtica. Responder EIDER abril 28, 2010 a las 1:40 am OIGA UN FAVOR NO LO PODRIA COLOCAR PARA VISUAL BASIC ME GUSTA TRABAJAR MAS EN VISUAL BASIC KE EN C++ LE AGRADESERIA UN MONTON Responder Alfredo Granda abril 30, 2010 a las 12:36 am Personalmente, no me gusta Visual Basic. Pero en lo que respecta a este ejemplo, la conversin a Visual Basic es casi inmediata ya que utiliza las libreras de .NET que son iguales en ambos lenguajes. Con un poco de tiempo deberas poder pasarlo a visual basic sin problemas. Responder EIDER mayo 20, 2010 a las 1:49 am sikas yaa gracias aunke mas rapido lo hise ke en pasarlo jajajajajaja pero stuvo bueno el tuyo Responder

YG abril 30, 2010 a las 7:05 am Oie Este Tutorial me hubiera salvado la vida hace unas semanas jaja ya ke estoy haciendo un compialdor para un clase de la universidad y ne el analisis lexico kice hacer un editor de texto. el codigo que use fue mucho y aun tenia el parpadeo pero ahora ocn este grandisimo tutorial prodre realizar un mejor trabajo de ante mano gracias Responder Ivan mayo 9, 2010 a las 2:24 pm Quisiera saber una forma igual que lo hiciste con los textos comentados pero que en lugar de que empiece con comillas, empiece con { y termine con }, muchisimas gracias, realmente me sirvi Responder Alfredo Granda mayo 18, 2010 a las 3:48 pm Simplemente tienes que crear un Regular Expression que coincida con lo que buscas. Responder Pregunton mayo 10, 2010 a las 11:35 am Hola, gracias por el ejemplo y est muy bueno, me sirvi. Pero ahora tengo una duda y me est costando encontrar la respuesta si yo quiero setear el richtextbox para que desde ah en adelante se escriba con un color, o en negrita, o lo que sea, cmo se hace? Por ej. colocar un botn que diga Negrita y una vez apretado todo lo que escriba de ah en adelante lo haga en negrita, y vuelto a apretar se quite y pueda escribir normal, pero sin que cambie lo que ya est escrito. Como un editor de texto comn. Espero no molestar mucho con mi pregunta y disculpen si es muy boluda pero no encuentro la respuesta. Muchas gracias, saludos. Responder Alfredo Granda mayo 18, 2010 a las 3:50 pm

Al inicio del cdigo selecciono todo el texto y lo pongo en color negro. Lo que tienes que hacer es casi lo mismo pero asegurarte de que el texto que selecciones llegue al final de tal forma que se va a continuar escribiendo en negrita. Responder David Velarde noviembre 4, 2010 a las 1:55 pm Tengo una pregunta, esto sirve para encontrar cadenas de texto exactas, pero si quisiese que no ubiera diferencias entre encontrar una palabra Vida vida ViDa sin importar que sea minuscula o mayuscula, como le haria? Responder Alfredo Granda mayo 26, 2011 a las 11:17 pm Tendras que utilizar Regular Expressions. Te recomiendo que visites el link que recomiendo en dicha seccin. Responder Guillermo febrero 6, 2011 a las 10:45 pm saludos la duda es cargo el codigo a comparar pero donde ejecuto todo esto en un bonton? que parametros llevaria ese boton para poder ejecutar esto Responder Alfredo Granda mayo 26, 2011 a las 11:08 pm El cdigo va dentro del evento Text Changed del TextBox Responder Franc junio 14, 2011 a las 5:27 pm Excelente Aporte!.. fuera bueno que hicieras uno usando tablas hash.. Responder Andersson

septiembre 20, 2011 a las 12:51 pm Excelente, fucione este cdigo con otro que tena y me funcion perfecto, mil gracias. Responder javicho octubre 11, 2011 a las 2:03 pm wow gracias mano te pasaste Responder

También podría gustarte