# Paleta de comandos

> Una paleta de comandos con búsqueda difusa y atajos. Un componente nativo de Pyzed para GUIs de escritorio en Python, con vista previa, ejemplos y su API.

Source: https://albakore.github.io/pyzed/es/library/command-palette/

:::tip[En pocas palabras]
Un buscador de todas las acciones de la app: escribe lo que quieres hacer y pulsa Enter.
:::

Una paleta de comandos: filtra `commands` (`ui.PaletteItem(label, on_press, keys=)`) por `query` con búsqueda difusa, resalta las letras encontradas y muestra cada atajo. La consulta y el índice `selected` son tuyos; Enter llama a `on_submit`.

`ui.command_palette` · Categoría: [Capas flotantes](https://albakore.github.io/pyzed/es/library/#capas-flotantes) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#command_palette)

**Código:**

```python
ui.command_palette("tog", on_query, [
    ui.PaletteItem("editor: toggle soft wrap", on_wrap, keys="alt-z"),
    ui.PaletteItem("theme selector: toggle", on_theme, keys="ctrl-k ctrl-t"),
    ui.PaletteItem("workspace: toggle left dock", on_left, keys="ctrl-b"),
    ui.PaletteItem("terminal panel: toggle", on_terminal, keys="ctrl-j"),
], selected=0, width=520)
```

## Cuándo usarlo

- Para que todas las acciones se puedan usar con el teclado (normalmente con Ctrl+Shift+P).

## Uso

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

class App(pz.App):
    def __init__(self):
        self.open, self.query, self.selected = False, "", 0

    def commands(self):
        return [ui.PaletteItem("editor: toggle soft wrap", self.toggle_wrap, keys="alt-z"),
                ui.PaletteItem("workspace: toggle left dock", self.toggle_left, keys="ctrl-b")]

    def on_key(self, combo):
        if combo == "ctrl-shift-p":
            self.open, self.query, self.selected = True, "", 0
            return pz.Command.focus("command-palette")
        if self.open and combo in ("up", "down"):
            self.selected += 1 if combo == "down" else -1
        elif combo == "escape":
            self.open = False

    def run_selected(self):
        matches = ui.fuzzy_filter(self.query, self.commands(), key=lambda c: c.label)
        if matches:
            self.open = False
            return matches[self.selected % len(matches)][0].on_press()

    def view(self):
        palette = ui.command_palette(self.query, lambda q: setattr(self, "query", q), self.commands(),
                                     selected=self.selected, on_submit=self.run_selected)
        return ui.layer(self.main_view(), palette if self.open else None,
                        on_dismiss=lambda: setattr(self, "open", False))
```

## 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.
:::

### Búsqueda

```python
ui.command_palette("", on_query, [
    ui.PaletteItem("file: new", on_new, keys="ctrl-n"),
    ui.PaletteItem("file: open", on_open, keys="ctrl-o"),
    ui.PaletteItem("theme selector: toggle", on_theme),
], width=420)
```

```python
ui.command_palette("op", on_query, [
    ui.PaletteItem("file: new", on_new, keys="ctrl-n"),
    ui.PaletteItem("file: open", on_open, keys="ctrl-o"),
    ui.PaletteItem("workspace: open recent", on_recent, keys="ctrl-r"),
], width=420)
```

```python
ui.command_palette("", on_query, [
    ui.PaletteItem("file: new", on_new, keys="ctrl-n"),
    ui.PaletteItem("file: open", on_open, keys="ctrl-o"),
    ui.PaletteItem("file: save", on_save, keys="ctrl-s"),
], selected=1, width=420)
```

## Eventos

Paleta de comandos tiene **3 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_query` | `ui.command_palette` | `(text)` | Callable que recibe el texto nuevo. |
| `on_submit` | `ui.command_palette` | `()` | Mensaje o callable que se envía al pulsar Enter. |
| `on_press` | `ui.PaletteItem` | `()` | Mensaje o callable que se envía al pulsar. `None` deshabilita el control. |

**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 App(pz.App):
    def __init__(self):
        self.open, self.query, self.wrap = True, "", False

    def toggle_wrap(self):
        self.wrap, self.open = not self.wrap, False

    def commands(self):                  # each item's on_press runs the command
        return [ui.PaletteItem("editor: toggle soft wrap", self.toggle_wrap, keys="alt-z")]

    def run_first(self):                 # on_submit: Enter runs the first match
        matches = ui.fuzzy_filter(self.query, self.commands(), key=lambda c: c.label)
        return matches[0][0].on_press() if matches else None

    def view(self):
        palette = ui.command_palette(self.query, lambda q: setattr(self, "query", q),   # on_query
                                     self.commands(), on_submit=self.run_first)
        return ui.layer(main_view(), palette if self.open else None,
                        on_dismiss=lambda: setattr(self, "open", False))
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Query:
    text: str

class App(pz.App):
    open, query, wrap = True, "", False

    def update(self, message):
        match message:
            case Query(text):
                self.query = text
            case "toggle wrap" | "submit":
                self.wrap, self.open = not self.wrap, False

    def view(self):
        palette = ui.command_palette(self.query, Query,
                                     [ui.PaletteItem("editor: toggle soft wrap", "toggle wrap")],
                                     on_submit="submit")
        return ui.layer(main_view(), palette if self.open else None)
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    query: str = ""
    wrap: bool = False

def view(state, set_state):
    items = [ui.PaletteItem("editor: toggle soft wrap", lambda: set_state(wrap=not state.wrap))]
    return ui.command_palette(state.query, lambda q: set_state(query=q), items,
                              on_submit=lambda: set_state(wrap=not state.wrap))
```

## Propiedades y API

### `ui.command_palette`

```python
command_palette(
    query,
    on_query,
    commands,
    *,
    selected=0,
    on_submit=None,
    placeholder='Execute a command…',
    input_id='command-palette',
    theme=None,
    **kwargs,
)
```

Una paleta de comandos: filtra `commands` por `query` con búsqueda difusa y muestra sus atajos.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `query` | *obligatorio* | Texto buscado. |
| `commands` | *obligatorio* | Lista de `PaletteItem`. |
| `selected` | `0` | Índice resaltado (para navegar con flechas). |
| `placeholder` | `"Execute a command…"` | Texto de ayuda cuando está vacío. |
| `input_id` | `"command-palette"` | Id del campo (para `Command.focus`). |
| `theme` | `None` | Tema a usar en lugar del actual (`pyzed.theme.current()`). |
| `**kwargs` | — | Los de `picker`. |

Eventos: `on_query`, `on_submit` ([eventos](#eventos)).

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

### `ui.PaletteItem`

```python
@dataclass
class PaletteItem(label, on_press=None, keys=None, icon=None, detail=None)
```

Una entrada de `command_palette` o `picker`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `label` | *obligatorio* | Texto de la etiqueta. |
| `keys` | `None` | Atajo que se muestra al final, escrito como texto: `"ctrl-s"`, `"cmd-k cmd-s"`. |
| `icon` | `None` | Nombre de un icono de Lucide (`pyzed icons` los lista). |
| `detail` | `None` | Texto secundario (por ejemplo, la ruta de un archivo). |

Eventos: `on_press` ([eventos](#eventos)).

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

## Relacionados

- [Buscador](https://albakore.github.io/pyzed/es/library/picker/): Una lista con búsqueda en una superficie flotante, con coincidencia difusa.
- [Capa](https://albakore.github.io/pyzed/es/library/layer/): Dibuja una capa encima de tu vista; al pulsar fuera se cierra.
- [Kbd](https://albakore.github.io/pyzed/es/library/kbd/): Atajos de teclado dibujados como teclas, con símbolos en macOS.
