codeeditor — u_pbt_codeeditor #
← Referencia de componentes · Índice de la guía
Editor de código con resaltado de sintaxis: diez lenguajes, números de línea, plegado de regiones, búsqueda y reemplazo, marcadores de diagnóstico en el margen y arrastre de archivos.
▶ Verlo en vivo — Aplicación de demostración, mosaico Code editor: la vista previa, el código que lo genera y esta página, uno al lado del otro.
De un vistazo #
| Userobject | u_pbt_codeeditor |
| Clase de items | — (componente sin items) |
| Sirve para | Escribir o mostrar código, una consulta SQL, un archivo de configuración: allí donde un multilineedit resulta poco legible |
| Opciones opt-in | ib_track_caret, ib_allow_drop, ib_folding |
Inicio rápido #
// event open de la ventana
uo_editor.is_syntax = uo_editor.SYNTAX_SQL
uo_editor.is_text = "SELECT c.name, SUM(o.amount) AS total~r~n" &
+ "FROM customer c~r~n" &
+ "WHERE o.status = 'paid'"
// Local variables
string ls_sql
// Releer lo que el usuario ha escrito realmente
ls_sql = uo_editor.of_get_text()
is_textdevuelve lo mismo: lo que escribe el usuario llega ahí en cuanto la escritura se asienta (eventue_changed).
Lenguajes reconocidos #
is_syntax acepta una de estas constantes, o SYNTAX_NONE (cadena vacía) para texto sin formato, sin resaltado.
| Lenguaje | Constante | Otras grafías aceptadas |
|---|---|---|
| PowerScript | SYNTAX_POWERSCRIPT | pb, powerbuilder |
| SQL | SYNTAX_SQL | tsql, plsql |
| JavaScript | SYNTAX_JAVASCRIPT | js, jsx |
| JSON | SYNTAX_JSON | jsonc |
| Familia C | SYNTAX_C · SYNTAX_CPP · SYNTAX_CSHARP · SYNTAX_JAVA | c++, cxx, cs |
| HTML / XML | SYNTAX_HTML · SYNTAX_XML | htm, xhtml, svg |
| CSS | SYNTAX_CSS | scss, less |
| Python | SYNTAX_PYTHON | py |
| YAML | SYNTAX_YAML | yml |
| Markdown | SYNTAX_MARKDOWN | md, mkd |
Los lenguajes de una misma familia comparten el resaltado (SYNTAX_JAVA colorea como SYNTAX_C, SYNTAX_XML como SYNTAX_HTML): la constante que elija documenta su intención, el resultado en pantalla es el mismo. El valor no distingue mayúsculas de minúsculas y un nombre desconocido recurre al texto sin formato, sin error.
Propiedades #
Contenido y lenguaje #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
is_text | string | "" | El código mostrado en el editor. En lectura, devuelve el contenido vivo, incluido lo que ha escrito el usuario, con los finales de línea recibidos: un texto en CRLF se relee en CRLF, un texto solo con CR en CR, plegado o no; un texto que los mezcla se relee en CRLF. Un texto nuevo se muestra desde su primera línea, borra los marcadores de of_add_marker y no está modificado (ib_modified) |
is_syntax | string | "" | Lenguaje de resaltado: constantes SYNTAX_* (véase la tabla anterior). SYNTAX_NONE = texto sin formato. Se relee tal como se escribió: SYNTAX_CSHARP sigue siendo SYNTAX_CSHARP, aunque C# comparta la gramática de C |
ib_readonly | boolean | false | Editor de solo lectura: el usuario consulta sin poder modificar |
ib_modified | boolean | false | true en cuanto el texto difiere del declarado guardado: un is_text nuevo no está modificado, la escritura, of_insert_text o un reemplazo lo marcan como modificado, deshacer hasta el texto guardado lo devuelve a false. Vuelva a ponerlo en false tras guardar; true lo fuerza |
Visualización #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
ib_line_numbers | boolean | true | Muestra u oculta el margen de números de línea, a la izquierda; ocultos, un margen estrecho conserva los marcadores de plegado y los diagnósticos de of_add_marker |
ib_current_line | boolean | true | Resalta la línea en la que se encuentra el cursor; en modo ib_wrap la banda cubre todas las filas de la línea |
ib_folding | boolean | false | Opt-in: permite plegar las regiones #region … #endregion (//#region en PowerScript, JavaScript o C) desde el margen: #region empieza plegada, #regionopen abierta; los marcadores siguen ahí incluso con ib_line_numbers = false. Es un modo de lectura: mientras está activo el editor no acepta escritura, porque el área de entrada contiene entonces el texto plegado y no el código fuente; activarlo sobre regiones cerradas también olvida el historial de Ctrl+Z. Un marcador se alcanza con el teclado (Tab); Intro o Espacio lo pliega o despliega |
ib_wrap | boolean | false | Ajusta las líneas largas al ancho en lugar de desplazarse lateralmente |
ii_tab_size | integer | 4 | Número de columnas que ocupa una tabulación, de 1 a 12 (cualquier otro valor vuelve a 4); Intro tras una llave de apertura sangra con este ancho |
is_font_family | string | "" | Fuente del editor (vacío = fuente monoespaciada del tema) |
ii_font_size | integer | 0 | Tamaño de la fuente en píxeles (0 = tamaño del tema) |
Navegación e interacciones #
| Propiedad | Tipo | Predeterminado | Función |
|---|---|---|---|
ib_search_enabled | boolean | true | Activa la barra de búsqueda integrada (Ctrl+F, Ctrl+H para reemplazar — véase «Teclado»); en false, of_find devuelve -4 |
ib_find_match_case | boolean | false | Opción de búsqueda: solo encuentra el texto con las mismas mayúsculas y minúsculas. El botón Aa de la barra es el mismo interruptor; vale para of_find, of_replace y of_replace_all |
ib_find_whole_word | boolean | false | Opción de búsqueda: solo encuentra el texto como palabra completa (el _ forma parte de la palabra: ls_a no se encuentra dentro de ls_ab). Botón ab de la barra |
ib_find_regex | boolean | false | Opción de búsqueda: el texto es una expresión regular (sintaxis JavaScript); el reemplazo de of_replace puede usar entonces $1, $& y $<name>. Una expresión no válida no encuentra nada, enmarca el campo en rojo y hace que of_replace devuelva -5. Botón .* de la barra |
il_doc_line | long | 0 | Lleva la línea indicada al centro de la vista y la marca con una banda de acento (numeración a partir de 1, como el margen) — la línea que señala una documentación o un resultado de búsqueda. El cursor y la selección del usuario no se mueven (il_caret_line mueve el cursor). Una línea oculta en una región plegada abre esa región; la banda también se pinta en modo ib_wrap. 0 borra la banda; una línea más allá del final no marca nada y se relee tal como se escribió; cualquier is_text nuevo borra la banda |
il_caret_line | long | 1 | La línea del cursor, a partir de 1, leída en vivo (plegado: la del margen). Escribirla pone el cursor al inicio de esa línea y la lleva a la pantalla — el «ir a la línea» de un error de compilación; una línea oculta en una región plegada abre esa región, una línea más allá del final se detiene en la última. Con ib_track_caret, ue_caret_changed sigue, como con un clic — nada cuando el cursor no se mueve |
il_caret_column | long | 1 | La columna del cursor, a partir de 1, leída en vivo: la posición del carácter en su línea (una tabulación cuenta como uno). Escribirla mueve el cursor a lo largo de su línea; más allá del final de la línea se detiene en ese final. Con ib_track_caret, ue_caret_changed sigue, como con un clic |
ib_track_caret | boolean | false | Opt-in: dispara ue_caret_changed en cada desplazamiento del cursor — gesto del usuario u orden de su código; un documento nuevo (is_text, una carga) no dice nada del cursor |
ib_allow_drop | boolean | false | Opt-in: acepta soltar archivos desde el Explorador de Windows; las rutas completas llegan por ue_drop_files |
is_theme_style | string | "" | Estilo visual del componente (constantes THEME_STYLE_*); vacío = el de la aplicación, seguido en cada cambio |
is_theme_mode | string | "" | Variante clara u oscura (constantes THEME_MODE_*); vacío = la de la aplicación, seguida en cada cambio |
il_theme_accent | long | -1 | Color de acento de este componente (-1 = acento de la aplicación, o el del tema) |
is_tooltip | string | "" | Tooltip simple mostrado al pasar el ratón por el componente |
is_super_tooltip_title | string | "" | Título del tooltip enriquecido (prevalece sobre is_tooltip) |
is_super_tooltip_text | string | "" | Texto del tooltip enriquecido (se acepta el marcado enriquecido) |
is_super_tooltip_image | string | "" | Imagen del tooltip enriquecido |
Métodos #
| Método | Función |
|---|---|
of_get_text ( ) → string | Devuelve el contenido vivo: el mismo valor que is_text, para el código que prefiere una llamada a método |
of_find (string as_text) | Abre la barra de búsqueda, escribe en ella el texto y resalta todas sus apariciones, según las opciones ib_find_* (plegado, solo en las líneas visibles). La primera aparición a partir del cursor se lleva a la pantalla; el cursor solo se mueve cuando el usuario cierra la barra. Un texto vacío vacía el campo y borra los resaltados. Devuelve 0 una vez aplicado, -4 cuando ib_search_enabled vale false, -2 si el componente no está creado |
of_insert_text (string as_text) | Inserta texto en el cursor, exactamente como si el usuario lo hubiera escrito: la selección actual se reemplaza, el cursor queda tras la inserción y esta se lleva a la pantalla. Es el método de un botón insertar un fragmento, allí donde is_text tiraría el trabajo en curso. Durante una búsqueda, la inserción va al cursor del usuario, nunca sobre la coincidencia. Cuando el foco está en el editor o en su barra de búsqueda, la inserción pasa por el camino de edición del navegador: Ctrl+Z todavía la deshace. Dispara ue_changed, y con ib_track_caret ue_caret_changed sigue, como con una escritura. No se inserta nada mientras el editor está en solo lectura (ib_readonly) o plegado (ib_folding). Devuelve 0 una vez aplicado, -4 en solo lectura o plegado, -5 con un texto vacío, -2 si el componente no está creado |
of_replace (string as_find, string as_replace) | Reemplaza la primera aparición de as_find a partir del cursor (volviendo al principio) y la lleva a la pantalla; se aplican las opciones ib_find_*, y con ib_find_regex el reemplazo puede usar $1, $& y $<name>. Un Ctrl+Z lo deshace. Con ib_track_caret, ue_caret_changed sigue cuando el cursor se mueve. Devuelve el número de apariciones reemplazadas (1, o 0 si no hay ninguna), -4 en solo lectura o plegado, -5 con una búsqueda vacía o una expresión no válida, -2 si el componente no está creado |
of_replace_all (string as_find, string as_replace) | Reemplaza todas las apariciones de as_find, en un solo paso de deshacer. Mismas opciones y mismos códigos que of_replace; devuelve el número de apariciones reemplazadas |
of_selected_text ( ) → string | Devuelve el texto que el usuario ha seleccionado, leído en vivo ("" sin selección), con los finales de línea de is_text |
of_select_range (long al_from_line, long al_from_col, long al_to_line, long al_to_col) | Selecciona de (línea, columna) a (línea, columna), todo a partir de 1, y lleva la selección a la pantalla; el cursor se sitúa en el extremo indicado en último lugar, y una columna más allá del final de su línea se detiene en ese final. Con ib_track_caret, ue_caret_changed sigue, como con un arrastre. Devuelve 0 una vez aplicado, -5 con una línea fuera del documento o una columna inferior a 1, -4 cuando el editor está plegado, -2 si el componente no está creado |
of_line_count ( ) | Devuelve el número de líneas del documento, plegado o no, leído en vivo — el límite de un cuadro «ir a la línea» |
of_add_marker (long al_line, string as_kind, string as_tooltip) | Marca una línea del margen con un diagnóstico — MARKER_ERROR, MARKER_WARNING o MARKER_INFO — y un tooltip (se acepta el marcado): lo que dice un compilador, allí donde lo dice. Varios marcadores pueden compartir una línea: el más grave da el icono, el tooltip los lista todos. Pertenecen al documento: un is_text nuevo los borra. Devuelve 0 una vez aplicado, -5 con una línea fuera del documento o un tipo desconocido, -2 si el componente no está creado |
of_remove_marker (long al_line) | Retira todos los marcadores de una línea. Devuelve 0 una vez retirados, -5 si la línea no tiene ninguno, -2 si el componente no está creado |
of_clear_markers ( ) | Retira todos los marcadores del margen. Devuelve 0 una vez aplicado, -2 si el componente no está creado |
of_marker_count ( ) | Devuelve el número de marcadores del margen, leído en vivo (dos en una línea cuentan como dos) |
of_reset ( ) | Restablece todas las propiedades a su valor predeterminado y vacía el editor. Devuelve 0 una vez aplicado, -2 si el componente no está creado |
of_set_redraw (boolean) | Agrupa una ráfaga de modificaciones en una sola representación. Devuelve 0 una vez aplicado, -2 si el componente no está creado |
of_save_as_png (string) · of_save_as_jpg (string) | Exporta la representación como imagen. Devuelve 0 una vez escrita la imagen, -4 si la escritura falla, -2 si el componente no está creado |
Eventos #
| Evento | Se activa cuando |
|---|---|
ue_changed ( ) | El usuario ha modificado el contenido y su escritura se ha asentado — también se dispara tras of_insert_text o un reemplazo. El evento no lleva nada: rellenarlo obligaba a releer todo el documento en cada pulsación asentada, para una aplicación que casi siempre solo quiere saber que ha cambiado. Quien quiera el código lo pide — is_text o of_get_text(); ib_modified dice si difiere del texto guardado |
ue_caret_changed (long al_line, long al_col) | El cursor se ha movido (tecla, clic, arrastre, escritura, o su código); línea y columna contadas a partir de 1, la línea es la del margen cuando el editor está plegado, la columna la posición del carácter en su línea (una tabulación cuenta como uno). Su código lo dispara como el gesto (il_caret_line, il_caret_column, of_select_range, of_insert_text, of_replace); nada cuando el cursor no se mueve, y un documento nuevo (is_text, una carga) no dice nada del cursor — requiere ib_track_caret = true |
ue_find_result (long al_count, long al_index) | Una búsqueda ha terminado, o pasa a otra aparición: al_count apariciones encontradas, al_index = posición de la que está destacada (a partir de 1). Durante la escritura solo se lanza si cambia el recuento; cerrar la barra no lo lanza; tampoco una búsqueda vacía |
ue_drop_files (string as_files[]) | Se han soltado archivos desde Windows: rutas completas, una entrada por archivo. Requiere ib_allow_drop = true |
ue_drag_enter ( ) | Un arrastre de archivos entra en el editor (ib_allow_drop) |
ue_drag_leave ( ) | El arrastre de archivos abandona el editor |
ue_ready ( ) | El componente ha terminado de cargarse; todo lo enviado antes se ha reproducido |
ue_runtime_missing ( ) | El runtime WebView2 está ausente: el componente permanece vacío |
ue_bg_color (long al_color) | El componente ha calculado el color de fondo de su tema; el userobject ya lo ha adoptado (backcolor) |
Teclado #
| Tecla | Efecto |
|---|---|
| Tab | Sangra hasta la siguiente tabulación (ii_tab_size); varias líneas seleccionadas: sangra todo el bloque |
| Mayús+Tab | Reduce la sangría de la línea o del bloque |
| Intro | Nueva línea con la misma sangría, un nivel más tras {, ( o [ |
| Ctrl+F | Abre la barra de búsqueda, rellenada con la selección (ib_search_enabled) |
| Ctrl+H | Abre la barra con su fila de reemplazo (solo editor modificable) |
| F3 · Mayús+F3 | Coincidencia siguiente · anterior, desde el código o la barra |
| Intro · Mayús+Intro (barra) | Coincidencia siguiente · anterior; en el campo de reemplazo, Intro reemplaza la coincidencia actual y Ctrl+Intro las reemplaza todas |
| Esc | Cierra la barra y pone el cursor en la coincidencia actual |
| Tab, luego Intro o Espacio (margen) | Alcanza un marcador de plegado y lo pliega o despliega (ib_folding) |
La columna que indican ue_caret_changed e il_caret_column es la posición del carácter en su línea: una tabulación cuenta como uno, sea cual sea su anchura en pantalla.
Ejemplos #
Un editor de consultas SQL #
// Congelar el dibujo durante la configuracion
uo_query.of_set_redraw(/*on*/ false)
// Coloreado SQL y luego la consulta que mostrar
uo_query.is_syntax = uo_query.SYNTAX_SQL
uo_query.is_text = "-- Mejores clientes por facturacion cobrada~r~n" &
+ "SELECT c.name, SUM(o.amount) AS total~r~n" &
+ "FROM customer c~r~n" &
+ " INNER JOIN orders o ON o.cust_id = c.id~r~n" &
+ "WHERE o.status = 'paid'~r~n" &
+ "GROUP BY c.name~r~n" &
+ "ORDER BY total DESC"
// Un solo redibujado, todo a la vez
uo_query.of_set_redraw(/*on*/ true)
// event clicked de cb_execute
string ls_sql
// Ejecutar la consulta tal como se escribio
ls_sql = uo_query.of_get_text() // lo que el usuario ha escrito realmente
of_execute(ls_sql)
Un visor de solo lectura #
Ideal para presentar código generado, un registro o un extracto que el usuario debe leer sin modificarlo.
// Coloreado PowerScript
uo_preview.is_syntax = uo_preview.SYNTAX_POWERSCRIPT
// Un visor de solo lectura: sin cursor, sin margen, sin resaltado
uo_preview.ib_readonly = true // solo consulta, sin cursor de escritura
uo_preview.ib_line_numbers = false // oculta el margen de numeros
uo_preview.ib_current_line = false // sin resaltado de la linea actual
uo_preview.ib_wrap = true // ajusta al ancho en vez de desplazarse
uo_preview.ii_tab_size = 2 // tabulaciones mostradas en 2 columnas
// El codigo que mostrar
uo_preview.is_text = of_generate_code()
Seguir la posición del cursor en una barra de estado #
// Notificar cada movimiento del cursor (ue_caret_changed)
uo_editor.ib_track_caret = true // suscripcion explicita: si no, ningun evento
// event ue_caret_changed de uo_editor : (long al_line, long al_col)
uo_status.of_panel(/*key*/ "pos").is_text = "Línea " + String(al_line) + ", col. " + String(al_col)
Sin ib_track_caret, el cursor no informa de nada: este disparador es de frecuencia elevada y permanece desactivado mientras no lo solicite.
Buscar e ir a una línea #
// Abre la barra de busqueda y resalta todas las apariciones
uo_editor.of_find(/*text*/ "ll_total")
// event ue_find_result de uo_editor : (long al_count, long al_index)
if al_count = 0 then
uo_status.of_panel(/*key*/ "main").is_text = "Ninguna aparición"
else
uo_status.of_panel(/*key*/ "main").is_text = String(al_index) + " / " + String(al_count)
end if
// Ir a la linea que ha senalado un compilador y marcarla en el margen
uo_editor.of_add_marker(/*line*/ ll_error_line, /*kind*/ uo_editor.MARKER_ERROR, /*tooltip*/ ls_error_text)
uo_editor.il_caret_line = ll_error_line // el cursor va alli, la linea llega a la pantalla
uo_editor.of_focus_webview() // el usuario corrige enseguida
Abrir un archivo soltado desde el Explorador #
// Accept files dropped from the Explorer
uo_editor.ib_allow_drop = true
// event ue_drop_files de uo_editor : (string as_files[])
string ls_content
integer li_file
// as_files[1] lleva la ruta COMPLETA del primer archivo soltado
li_file = FileOpen(as_files[1], StreamMode!, Read!)
if li_file > 0 then
FileReadEx(li_file, ls_content)
FileClose(li_file)
// Colorear segun la extension del archivo y mostrar su contenido
uo_editor.is_syntax = of_syntax_for_extension(as_files[1])
uo_editor.is_text = ls_content
end if
Reaccionar a las modificaciones #
// event ue_changed de uo_editor : ( )
cb_save.enabled = uo_editor.ib_modified // deshacer hasta el texto guardado lo devuelve a false
// event clicked de cb_save
if of_save_script(uo_editor.is_text) = 1 then
uo_editor.ib_modified = false // el texto guardado pasa a ser la referencia
cb_save.enabled = false
end if
El evento solo se dispara una vez que la escritura se ha estabilizado: escribir de forma continua no genera un evento por tecla.
Renombrar una variable en todo el script #
// Local variables
long ll_count
// Solo palabras completas: ll_total2 es otra variable
uo_editor.ib_find_whole_word = true
ll_count = uo_editor.of_replace_all(/*find*/ "ll_total", /*replace*/ "ldc_amount") // un solo Ctrl+Z lo deshace todo
Buenas prácticas #
- Asigne siempre
is_syntaxantes queis_text: el código aparece coloreado desde la primera visualización, sin recoloración visible. - Para una presentación en modo consulta, la combinación
ib_readonly+ib_line_numbers = false+ib_wrapda un visor sobrio que ya no parece un editor. - Para recuperar lo escrito, lea
is_text(oof_get_text()) una vez asentada la escritura, — es decir, dentro de suue_changed, que le dice cuándo. ib_foldingsolo resulta interesante en archivos largos y estructurados; déjelo desactivado para extractos breves. Apáguelo antes de permitir modificaciones: un esquema plegado se lee, no se edita, yof_get_text()devuelve siempre el código fuente completo, regiones cerradas incluidas.- Enmarque la carga de un archivo grande con
of_set_redraw(false)/of_set_redraw(true). - Llame a
of_reset()antes de cargar un documento de otra naturaleza: sin ello, el lenguaje, el tamaño de tabulación o el modo de solo lectura anteriores siguen vigentes. - Tras guardar, vuelva a poner
ib_modifiedenfalse: vuelve a sertrueen la primera pulsación, yfalsesi el usuario deshace hasta el texto guardado. - Para mostrar los errores de una compilación,
of_clear_markers()y luego unof_add_markerpor diagnóstico, eil_caret_lineen el primero.
Heredado de la base común #
Estos miembros existen en todos los componentes visuales — no son propios de este. Se detallan una sola vez, en los capítulos transversales; esta tabla solo dice dónde leerlos.
| Miembros | Función | Detallado en |
|---|---|---|
of_reset | Poner el componente a cero | 3.6 Poner un componente a cero: of_reset() |
of_register_shortcut · of_clear_shortcuts | Atajos de teclado del componente | 3.5 Los atajos de teclado |
of_is_created · of_is_ready · of_get_last_error | Si ha nacido, si está listo, qué ha fallado | 3.7 Diagnóstico |
of_save_as_png · of_save_as_jpg | Exportar el render como imagen | 3.8 Exportar la representación como imagen |
of_set_redraw | Agrupar los cambios en un solo repintado | 3.10 Buenas prácticas |
of_preload_icons | Iconos mostrados sin retardo | Visualización instantánea: of_icon |
of_set_translation | Traducir una etiqueta del componente | 5.2 Adaptar una etiqueta: of_set_translation |
of_focus_webview | Dar el foco al componente | 6.4 Teclado y foco |
of_print · of_print_to_pdf | Imprimir, o escribir un PDF | 6.9 Imprimir |
of_set_property · of_get_property · of_component_name | Controlar una propiedad por su nombre | 3.1 El motor de propiedades |
Dos ayudas no se heredan: of_icon y of_escape_markup viven en n_pbt_utils. Declare uno — n_pbt_utils lnv_utils, nada que crear — y llámelas sobre él.