Documentation
¶
Overview ¶
Package command es el registro de comandos y el motor de atajos de FlowCode.
Por qué existe ¶
Sin él, cada widget acaba con un switch de teclas dentro. Eso funciona hasta que dos widgets quieren la misma combinación en momentos distintos —Escape cierra el panel emergente si hay uno abierto y si no vuelve al editor— y a partir de ahí nadie sabe qué hace cada tecla sin leerse el programa entero.
El modelo es el de VS Code, que es el que ha demostrado escalar: todo lo que hace el editor es un comando con nombre, los atajos apuntan a nombres, y cada atajo lleva una condición que dice cuándo está activo. La consecuencia práctica es que la paleta de comandos y el teclado son la misma tabla vista de dos maneras, y que reasignar teclas no toca ni una línea de código.
Cómo se nombran las teclas ¶
Un atajo es una cadena: "ctrl+shift+p". No un tipo enumerado, y es deliberado: esta capa está por debajo de la interfaz y no puede conocer sus teclas, y además ese es exactamente el formato en el que se escribirán los archivos de configuración. Tener una sola representación evita la traducción —y el desajuste— entre lo que se configura y lo que se ejecuta.
Index ¶
- Variables
- func NormalizeChord(chord string) (string, error)
- type Binding
- type Command
- type Context
- type Registry
- func (r *Registry) Available(ctx Context) []*Command
- func (r *Registry) Bind(chord, id, when string) error
- func (r *Registry) Bindings() []Binding
- func (r *Registry) Get(id string) (*Command, bool)
- func (r *Registry) Keys(id string) string
- func (r *Registry) Lookup(chord string, ctx Context) (*Command, bool)
- func (r *Registry) MustBind(chord, id, when string)
- func (r *Registry) Register(cmd Command)
- func (r *Registry) Run(id string, ctx Context) error
- type When
Constants ¶
This section is empty.
Variables ¶
var Always = When{}
Always es la condición que siempre se cumple, para los atajos globales.
Functions ¶
func NormalizeChord ¶
NormalizeChord pone una combinación en forma canónica: modificadores en orden fijo, en minúsculas y separados por '+'.
Sin normalizar, "Shift+Ctrl+P" y "ctrl+shift+p" serían atajos distintos, y el usuario que escribe el primero en su configuración se quedaría sin entender por qué no pasa nada.
Types ¶
type Binding ¶
type Binding struct {
// Chord es la combinación normalizada: "ctrl+shift+p".
Chord string
// Command es el identificador del comando.
Command string
// When puede ser más restrictiva que la del comando: la misma tecla puede
// hacer cosas distintas según dónde esté el foco.
When When
}
Binding ata un atajo a un comando.
type Command ¶
type Command struct {
// ID identifica al comando y es lo que referencian los atajos. Se nombra
// por ámbito y acción —"editor.borrarIzquierda"— para que la lista ordenada
// alfabéticamente quede agrupada por temas.
ID string
// Title es lo que se lee en la paleta.
Title string
// When limita cuándo tiene sentido. Un comando que no cumple su condición
// no aparece en la paleta ni se ejecuta.
When When
// Hidden lo deja fuera de la paleta sin quitarle el atajo.
//
// Es para lo que se hace con una tecla y nunca buscando por su nombre:
// mover el cursor a la izquierda es un comando como cualquier otro —y por
// eso se puede reasignar—, pero ofrecerlo en una lista de acciones sería
// enterrar lo útil entre cincuenta entradas que nadie va a elegir.
Hidden bool
// Run hace el trabajo. Devolver un error no lo aborta todo: lo recoge quien
// lo invocó, que es el único que sabe si conviene enseñarlo.
Run func() error
}
Command es una acción con nombre.
Todo lo que hace el editor pasa por aquí: la tecla, la entrada de la paleta y la llamada desde otro comando ejecutan exactamente lo mismo. Es lo que impide que el atajo y el menú acaben haciendo cosas ligeramente distintas.
type Context ¶
Context son las condiciones activas en un momento dado: qué tiene el foco, si hay selección, si el documento está modificado.
Es un mapa de banderas y no una estructura con campos porque quien las pone —la aplicación— y quien las lee —la condición de un atajo, escrita en un archivo de configuración— no se conocen entre sí. Una condición que menciona una bandera que nadie publica se evalúa como falsa, que es lo correcto: el atajo simplemente no se activa.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry guarda los comandos y los atajos.
No es seguro para uso concurrente: se construye al arrancar y se consulta desde el hilo de la interfaz.
func (*Registry) Available ¶
Available devuelve los comandos que pueden ejecutarse en un contexto, en el orden en que se registraron. Es lo que enseña la paleta.
func (*Registry) Bind ¶
Bind ata una combinación de teclas a un comando.
La condición se comprueba al registrar y no al pulsar: un atajo mal escrito debe romper al arrancar, cuando quien lo escribió lo está mirando, y no quedarse callado hasta que alguien pulse esa tecla dentro de tres semanas.
func (*Registry) Bindings ¶
Bindings devuelve todos los atajos, para diagnóstico y para la futura pantalla de configuración de teclado.
func (*Registry) Keys ¶
Keys devuelve el atajo de un comando, para enseñarlo junto a su nombre en la paleta. Con varios, devuelve el registrado más recientemente, que es el que va a ganar al pulsarlo.
func (*Registry) Lookup ¶
Lookup busca qué comando ejecuta una combinación en un contexto dado.
Gana el último atajo registrado que encaje. Es la regla de VS Code y la que permite que la configuración del usuario tape a la de por omisión sin tener que borrar nada: basta añadir el suyo después.
type When ¶
type When struct {
// contains filtered or unexported fields
}
When es una condición compilada.
Se compila una vez al registrar el atajo y se evalúa en cada pulsación. Al revés —volver a interpretar la cadena en cada tecla— funcionaría igual de bien y sería más lento en el camino más sensible a la latencia que tiene un editor: el que va de la tecla al píxel.
func MustParseWhen ¶
MustParseWhen es ParseWhen para las condiciones escritas en el código, que se conocen en tiempo de compilación y cuya sintaxis es un error del programa.
func ParseWhen ¶
ParseWhen compila una condición.
La gramática es la mínima que resuelve los casos reales: identificadores, negación, conjunción, disyunción y paréntesis. VS Code admite además comparaciones y expresiones regulares; se añadirán cuando aparezca la primera condición que las necesite y no antes, porque cada operador nuevo es una forma más de escribir un atajo que no se dispara y no se sabe por qué.