# Editor

> Un editor de código completo: resaltado, plegado, minimapa, marcas de git. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/editor/

:::tip[En pocas palabras]
Una caja para escribir código, con colores, números de línea y todo lo que espera un programador.
:::

Un editor de código con resaltado de sintaxis en los colores del tema (más de 100 lenguajes), números de línea, marcas de git, cierre automático de pares, plegado, minimapa y zoom de fuente. Es **no controlado**: el texto, el cursor y el historial viven en Rust, ligados al `id`, y `text` solo es el valor inicial. `on_change` recibe el texto completo y `on_cursor` la `(línea, columna)`. `pz.code_editor` es el widget base sin tema.

`ui.editor` · Categoría: [Código y herramientas](https://albakore.github.io/pyzed/es/library/#código-y-herramientas) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#editor)

**Código:**

```python
code = '''import pyzed as pz
from pyzed import ui

class Counter(pz.App):
    def __init__(self):
        self.count = 0

    def view(self):
        return ui.button(f"Clicks: {self.count}", self.increment)
'''
pz.container(ui.editor("counter.py", code, path="counter.py", markers={7: "modified", 10: "created"}),
             width=620, height=290)
```

## Cuándo usarlo

- Para código, archivos de configuración, registros editables o cualquier texto largo.
- Usa la ruta del archivo como `id`: cada archivo conserva su cursor e historial al cambiar de pestaña.
- Para reemplazar el texto desde código, devuelve `pz.Command.set_editor_text(id, text)`.

## Uso

```python
import pyzed as pz
from pyzed import ui

from pathlib import Path

class Editor(pz.App):
    def __init__(self):
        self.path = "main.py"
        self.text = Path(self.path).read_text()

    def save(self):
        Path(self.path).write_text(self.text)

    def view(self):
        return ui.editor(self.path, self.text, path=self.path,
                         on_change=lambda text: setattr(self, "text", text))
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Lenguaje

```python
pz.container(ui.editor("v-py", "class Counter(pz.App):\n    count = 0\n\n    def view(self):\n        return ui.button('Add', self.add)", path="counter.py"), width=470, height=110)
```

```python
pz.container(ui.editor("v-rs", "fn main() {\n    println!(\"hi\");\n}\n", language="rust"),
             width=420, height=90)
```

```python
pz.container(ui.editor("v-json", '{\n  "name": "notes",\n  "version": 2\n}\n', language="json"),
             width=420, height=110)
```

### Opciones

```python
pz.container(ui.editor("v-g", "class Counter(pz.App):\n    count = 0\n\n    def view(self):\n        return ui.button('Add', self.add)", path="a.py", gutter=False), width=470, height=110)
```

```python
pz.container(ui.editor("v-m", "class Counter(pz.App):\n    count = 0\n\n    def view(self):\n        return ui.button('Add', self.add)", path="a.py", markers={2: "created", 5: "modified"}),
             width=470, height=110)
```

```python
pz.container(ui.editor("v-mm", "class Counter(pz.App):\n    count = 0\n\n    def view(self):\n        return ui.button('Add', self.add)", path="a.py", minimap=True), width=470, height=124)
```

```python
pz.container(ui.editor("v-ws", "class Counter(pz.App):\n    count = 0\n\n    def view(self):\n        return ui.button('Add', self.add)", path="a.py", show_whitespace=True), width=470, height=110)
```

```python
pz.container(ui.editor("v-ph", "", placeholder="Write something…"), width=420, height=60)
```

```python
pz.container(ui.editor("v-fs", "print(\"big\")\n", path="a.py", font_size=16), width=420, height=60)
```

## Ejemplos

### Plegado, code lens y minimapa

Los bloques se pliegan por indentación (Ctrl+Shift+[ y ]), `annotations` añade un code lens encima de una línea y `minimap=True` dibuja la vista general a la derecha.

**Código:**

```python
code = '''import pyzed as pz
from pyzed import ui

class Counter(pz.App):
    def __init__(self):
        self.count = 0

    def increment(self):
        self.count += 1

    def view(self):
        return ui.button(f"Clicks: {self.count}", self.increment)
'''
pz.container(ui.editor("lens.py", code, path="counter.py", minimap=True, annotations={5: "1 reference"}),
             width=680, height=290)
```

### Cursor y espacios

`cursor_shape` es `"bar"`, `"block"`, `"underline"` o `"hollow"`; `show_whitespace=True` dibuja espacios y tabuladores; `wrap=True` parte las líneas largas.

**Código:**

```python
pz.container(ui.editor("ws.py", "def greet(name):\n    return f'Hello, {name}'\n",
                       path="ws.py", cursor_shape="block", show_whitespace=True, font_size=15),
             width=620, height=120)
```

## Eventos

Editor tiene **6 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | De | El handler recibe | Cuándo |
| --- | --- | --- | --- |
| `on_change` | `ui.editor`, `pz.code_editor` | `(text)` | Callable que recibe el nuevo valor. |
| `on_cursor` | `ui.editor`, `pz.code_editor` | `(line, column)` | Callable que recibe `(línea, columna)`. |
| `on_scroll` | `ui.editor`, `pz.code_editor` | `(info)` | Se llama al desplazar. |
| `on_zoom` | `ui.editor`, `pz.code_editor` | `(step)` | Callable que recibe `1`, `-1` o `0` con Ctrl+= / Ctrl+- / Ctrl+0 y Ctrl+rueda. |
| `on_action` | `ui.editor`, `pz.code_editor` | `(name)` | Callable que recibe el nombre de cada acción del editor que se ejecuta (`"undo"`, `"select_next"`…), por ejemplo para contarlas. |
| `on_hover` | `ui.editor`, `pz.code_editor` | `()` | Función que recibe `{line, column, start, end, x, y, height}` (la palabra bajo el ratón, desde 1, y su lugar en el editor) cuando el ratón se detiene sobre ella, y `None` cuando se va (tarjetas de información). |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Editor(pz.App):
    def __init__(self):
        self.text = "print('hello')\n"
        self.cursor = (1, 1)
        self.font_size = 14

    def zoom(self, step):                # on_zoom: 1, -1 or 0 (Ctrl+=, Ctrl+-, Ctrl+0)
        self.font_size = 14 if step == 0 else self.font_size + step

    def view(self):
        line, column = self.cursor
        return pz.column([
            ui.editor("main.py", self.text, path="main.py", font_size=self.font_size, height=200,
                      on_change=lambda text: setattr(self, "text", text),            # every edit
                      on_cursor=lambda ln, col: setattr(self, "cursor", (ln, col)),  # from 1
                      on_zoom=self.zoom,
                      on_action=lambda name: print("ran", name)),                    # "undo"...
            ui.status_bar([], [ui.status_item(f"Ln {line}, Col {column}")]),
        ])
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Edited:
    text: str

@dataclass
class Moved:
    line: int
    column: int

class Editor(pz.App):
    text, cursor = "print('hello')\n", (1, 1)

    def update(self, message):
        match message:
            case Edited(text):
                self.text = text
            case Moved(line, column):
                self.cursor = (line, column)

    def view(self):
        return ui.editor("main.py", self.text, path="main.py", height=200,
                         on_change=Edited, on_cursor=Moved)   # the classes build the messages
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    text: str = "print('hello')\n"
    line: int = 1
    column: int = 1

def view(state, set_state):
    return pz.column([
        ui.editor("main.py", state.text, path="main.py", height=200,
                  on_change=lambda text: set_state(text=text),
                  on_cursor=lambda line, column: set_state(line=line, column=column)),
        ui.label(f"Ln {state.line}, Col {state.column}"),
    ])
```

## Propiedades y API

### `ui.editor`

```python
editor(
    id,
    text='',
    *,
    language=None,
    path=None,
    on_change=None,
    on_cursor=None,
    markers=None,
    font_size=None,
    line_height=None,
    gutter=True,
    wrap=False,
    active_line=True,
    height='fill',
    placeholder=None,
    annotations=None,
    show_whitespace=False,
    tab_size=None,
    hard_tabs=False,
    backspace_unindent=True,
    repeat_delay=None,
    repeat_rate=None,
    capture_keys=(),
    on_scroll=None,
    auto_close=True,
    folding=True,
    minimap=False,
    cursor_shape='bar',
    cursor_blink=True,
    cursor_width=2.0,
    cursor_color=None,
    on_zoom=None,
    on_action=None,
    highlights=None,
    match_brackets=True,
    selection_highlight=True,
    font=None,
    keymap=None,
    scrollbar=True,
    readonly=False,
    on_hover=None,
    hover_delay=500,
    sticky_scroll=0,
    theme=None,
)
```

Un editor de código: resaltado con los colores del tema, números de línea y marcadores de git.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `id` | *obligatorio* | Identifica el buffer (usa la ruta del archivo). |
| `text` | `""` | Texto inicial. |
| `language` | `None` | Lenguaje. Si falta, se deduce de `path`. |
| `path` | `None` | Ruta del archivo. |
| `markers` | `None` | `{línea: "created" \| "modified" \| "deleted"}`. |
| `font_size` | `None` | Tamaño de la fuente (por defecto, el del tema). |
| `line_height` | `None` | Alto de línea. |
| `gutter` | `True` | Muestra los números de línea. |
| `wrap` | `False` | Ajuste de línea. |
| `active_line` | `True` | Color de fondo de la línea del cursor. |
| `height` | `"fill"` | Alto: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `placeholder` | `None` | Texto de ayuda cuando está vacío. |
| `annotations` | `None` | `{línea: "texto"}` o `{línea: ("texto", color)}`: texto virtual al final de la línea (code lens, diagnósticos). |
| `show_whitespace` | `False` | Dibuja los espacios como `·` y los tabuladores como `→`. |
| `tab_size` | `None` | Tab inserta espacios hasta el siguiente múltiplo; Enter mantiene la sangría (un nivel más tras `:`); Backspace quita un nivel. |
| `hard_tabs` | `False` | Con `tab_size`: Tab, Enter y sangrar (Ctrl+]) usan tabulaciones en vez de espacios. |
| `backspace_unindent` | `True` | Con `tab_size`: Backspace en los espacios iniciales quita un nivel entero (`False`: un espacio). |
| `repeat_delay` | `None` | Milisegundos que esperan Backspace y Suprimir, mantenidos, antes de repetirse (`None`: los del sistema). |
| `repeat_rate` | `None` | Borrados por segundo como máximo mientras se mantiene Backspace o Suprimir (`None`: el ritmo del sistema). |
| `capture_keys` | `()` | Teclas que el editor deja al `on_key` de la app (`"up"`, `"enter"`…), por ejemplo con una lista de autocompletado abierta. |
| `auto_close` | `True` | Cierra paréntesis, corchetes, llaves y comillas al escribir (y envuelve la selección). |
| `folding` | `True` | Flechas de plegado en el margen; Ctrl+Shift+[ pliega y Ctrl+Shift+] despliega. |
| `minimap` | `False` | `True` (o un ancho en píxeles) muestra un minimapa a la derecha. |
| `cursor_shape` | `"bar"` | `"bar"`, `"block"`, `"underline"` o `"hollow"`. |
| `cursor_blink` | `True` | Si el cursor parpadea. |
| `cursor_width` | `2.0` | Ancho del cursor de barra. |
| `cursor_color` | `None` | Color del cursor (por defecto, el color de jugador del tema). |
| `highlights` | `None` | Rangos pintados detrás del texto con el color de búsqueda del tema: `[(línea, columna, línea_final, columna_final)]`, desde 1, con el final excluido. |
| `match_brackets` | `True` | Remarca el corchete pareja del que está junto al cursor (Ctrl+M salta a él). |
| `selection_highlight` | `True` | Resalta las demás apariciones del texto seleccionado (Ctrl+D añade la siguiente como cursor). |
| `font` | `None` | Tipografía: `"mono"` por defecto; `"sans"` hace un cuadro de texto de varias líneas, como el cuadro de mensaje de un chat. |
| `keymap` | `None` | Diccionario `{atajo: acción}` al estilo de Zed (`{"ctrl-shift-d": "duplicate_line_down"}`); `None` como acción quita una tecla por defecto. Créalo a partir de cambios por acción con `pyzed.ui.editor.keymap_for`. |
| `scrollbar` | `True` | `False` oculta las barras de desplazamiento. |
| `readonly` | `False` | `True` deja seleccionar y copiar el texto, pero no cambiarlo (un log, un traceback). |
| `hover_delay` | `500` | Milisegundos que el ratón debe quedarse sobre una palabra antes de llamar a `on_hover`. |
| `sticky_scroll` | `0` | Cuántas líneas de los bloques que rodean al código visible (`class`, `def`, `if`…) quedan fijas arriba al desplazarse (`0`: ninguna). |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |

Eventos: `on_change`, `on_cursor`, `on_scroll`, `on_zoom`, `on_action`, `on_hover` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#editor)

### `ui.language_token`

```python
language_token(path)
```

Devuelve el token de lenguaje del resaltador para una ruta (`"main.rs"` → `"rs"`).

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `path` | *obligatorio* | Ruta del archivo. |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#language_token)

### `pz.code_editor`

```python
code_editor(
    id,
    text='',
    *,
    language='txt',
    size=14.0,
    line_height=None,
    font=None,
    width=None,
    height=None,
    padding=None,
    syntax=None,
    bg=None,
    color=None,
    selection_color=None,
    placeholder=None,
    placeholder_color=None,
    gutter=True,
    gutter_color=None,
    gutter_active_color=None,
    gutter_width=None,
    markers=None,
    wrap=False,
    on_change=None,
    on_cursor=None,
    active_line=None,
    scrollbar_color=None,
    annotations=None,
    whitespace=None,
    tab_size=None,
    capture_keys=None,
    on_scroll=None,
    auto_close=False,
    folding=False,
    minimap=None,
    minimap_thumb=None,
    cursor_shape='bar',
    cursor_width=2.0,
    cursor_blink=True,
    cursor_color=None,
    on_zoom=None,
    on_action=None,
    highlights=None,
    highlight_color=None,
    match_brackets=True,
    selection_highlight=True,
    keymap=None,
    scrollbar=True,
    readonly=False,
    hard_tabs=False,
    backspace_unindent=True,
    repeat_delay=None,
    repeat_rate=None,
    on_hover=None,
    hover_delay=500.0,
    sticky_scroll=0,
)
```

Un editor de código con resaltado de sintaxis, números de línea y marcadores de git, basado en
`text_editor` de Iced. Es **no controlado**: `text` solo es el valor inicial para ese `id`; el
texto, el cursor y el historial viven en Rust. Usa `Command.set_editor_text` para reemplazarlo.
Para el editor con tema usa [`ui.editor`](https://albakore.github.io/pyzed/es/components/code/).

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `id` | *obligatorio* | Identifica el buffer. Reutilízalo para conservar el estado entre renders. |
| `text` | `""` | Texto inicial. |
| `language` | `"txt"` | Extensión o nombre del lenguaje (`"py"`, `"rs"`, `"json"`…). |
| `size` | `14.0` | Tamaño de la fuente. |
| `line_height` | `None` | Alto de línea en píxeles. |
| `font` | `None` | Familia (por defecto, monoespaciada). |
| `width` | `None` | Ancho: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `height` | `None` | Alto: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `padding` | `None` | Relleno interior: `8`, `(vertical, horizontal)` o `(arriba, derecha, abajo, izquierda)`. |
| `syntax` | `None` | Mapa de scopes TextMate a colores (lo da `Theme.syntax_scopes()`). |
| `bg` | `None` | Color de fondo (`"#rrggbb[aa]"`, `(r, g, b[, a])` o `"transparent"`). |
| `color` | `None` | Color del texto o del icono. |
| `selection_color` | `None` | Color de la selección. |
| `placeholder` | `None` | Texto de ayuda cuando está vacío. |
| `placeholder_color` | `None` | Color del placeholder. |
| `gutter` | `True` | Muestra los números de línea. |
| `gutter_color` | `None` | Color de los números de línea. |
| `gutter_active_color` | `None` | Color del número de la línea del cursor. |
| `gutter_width` | `None` | Ancho del margen (automático por defecto). |
| `markers` | `None` | `{línea: color}` para las marcas de git del margen (líneas desde 1). |
| `wrap` | `False` | Ajuste de línea. |
| `active_line` | `None` | Color de fondo de la línea del cursor. |
| `scrollbar_color` | `None` | Color de la barra de desplazamiento. |
| `annotations` | `None` | `{línea: "texto"}` o `{línea: ("texto", color)}`: texto virtual al final de la línea (code lens, diagnósticos). |
| `whitespace` | `None` | Dibuja los espacios como `·` y los tabuladores como `→` en este color. |
| `tab_size` | `None` | Tab inserta espacios hasta el siguiente múltiplo; Enter mantiene la sangría; Backspace quita un nivel. |
| `capture_keys` | `None` | Teclas que el editor deja al `on_key` de la app (`"up"`, `"enter"`…), por ejemplo con una lista de autocompletado abierta. |
| `auto_close` | `False` | Al escribir un paréntesis, corchete, llave o comilla también inserta el de cierre. |
| `folding` | `False` | Flechas de plegado en el margen y Ctrl+Shift+[ / ]. |
| `minimap` | `None` | Ancho del minimapa en píxeles (`None`: sin minimapa). |
| `minimap_thumb` | `None` | Color del resaltado del área visible en el minimapa. |
| `cursor_shape` | `"bar"` | `"bar"`, `"block"`, `"underline"` o `"hollow"`. |
| `cursor_width` | `2.0` | Ancho del cursor de barra. |
| `cursor_blink` | `True` | Si el cursor parpadea. |
| `cursor_color` | `None` | Color del cursor. |
| `highlights` | `None` | Rangos pintados detrás del texto (resultados de búsqueda): `[(línea, columna, línea_final, columna_final)]`, desde 1, con el final excluido. |
| `highlight_color` | `None` | Color de `highlights`. |
| `match_brackets` | `True` | Remarca el corchete pareja del que está junto al cursor. |
| `selection_highlight` | `True` | Resalta las demás apariciones del texto seleccionado. |
| `keymap` | `None` | Diccionario `{atajo: acción}` al estilo de Zed; `None` como acción quita una tecla por defecto (`pyzed.ui.editor.keymap_for` crea uno a partir de cambios por acción). |
| `scrollbar` | `True` | `False` oculta las barras de desplazamiento. |
| `readonly` | `False` | `True` deja seleccionar y copiar el texto, pero no cambiarlo (un log, un traceback). |
| `hard_tabs` | `False` | Con `tab_size`: Tab, Enter y sangrar (Ctrl+]) usan tabulaciones en vez de espacios. |
| `backspace_unindent` | `True` | Con `tab_size`: Backspace en los espacios iniciales quita un nivel entero (`False`: un espacio). |
| `repeat_delay` | `None` | Milisegundos que esperan Backspace y Suprimir, mantenidos, antes de repetirse (`None`: los del sistema). |
| `repeat_rate` | `None` | Borrados por segundo como máximo mientras se mantiene Backspace o Suprimir (`None`: el ritmo del sistema). |
| `hover_delay` | `500.0` | Milisegundos que el ratón debe quedarse sobre una palabra antes de llamar a `on_hover`. |
| `sticky_scroll` | `0` | Cuántas líneas de los bloques que rodean al código visible (`class`, `def`, `if`…) quedan fijas arriba al desplazarse (`0`: ninguna). |

Eventos: `on_change`, `on_cursor`, `on_scroll`, `on_zoom`, `on_action`, `on_hover` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#code_editor)

## Relacionados

- [Terminal](https://albakore.github.io/pyzed/es/library/terminal/): Una vista de terminal de solo lectura con colores ANSI.
- [Consola](https://albakore.github.io/pyzed/es/library/console/): Un registro estilo dev tools con niveles, filtro, copiar y limpiar.
- [Espacio de trabajo](https://albakore.github.io/pyzed/es/library/workspace/): La disposición de una ventana estilo editor: barra de título, docks, centro y barra de estado.
