Un ejemplo completo (Extender LilyPond)

#### Un ejemplo completo

El ejemplo siguiente define una instrucción de marcado para trazar un rectángulo doble alrededor de un fragmento de texto.

En primer lugar, necesitamos construir un resultado aproximado utilizando marcados. Una consulta a Instrucciones de marcado de texto nos muestra que es útil la instrucción `\box`:

>     \markup \box \box HELLO

Ahora, consideramos que es preferible tener más separación entre el texto y los rectángulos. Según la documentación de `\box`, esta instrucción usa una propiedad `box-padding`, cuyo valor predeterminado es 0.2. La documentación también menciona cómo sobreescribir este valor:

>     \markup \box \override #'(box-padding . 0.6) \box A

Después, el relleno o separación entre los dos rectángulos nos parece muy pequeño, así que lo vamos a sobreescribir también:

>     \markup \override #'(box-padding . 0.4) \box
>          \override #'(box-padding . 0.6) \box A

Repetir esta extensa instrucción de marcado una y otra vez sería un quebradero de cabeza. Aquí es donde se necesita una instrucción de marcado. Así pues, escribimos una instrucción de marcado `double-box`, que toma un argumento (el texto). Dibuja los dos rectángulos y añade una separación.

    #(define-markup-command (double-box layout props text) (markup?)
      "Trazar un rectángulo doble rodeando el texto."
      (interpret-markup layout props
        #{\markup \override #'(box-padding . 0.4) \box
                \override #'(box-padding . 0.6) \box { #text }#}))

o, de forma equivalente,

    #(define-markup-command (double-box layout props text) (markup?)
      "Trazar un rectángulo doble rodeando el texto."
      (interpret-markup layout props
        (markup #:override '(box-padding . 0.4) #:box
                #:override '(box-padding . 0.6) #:box text)))

`text` es el nombre del argumento de la instrucción, y `markup?` es el tipo: lo identifica como un elemento de marcado. La función `interpret-markup` se usa en casi todas las instrucciones de marcado: construye un sello, usando `layout`, `props`, y un elemento de marcado. En el segundo caso, la marca se construye usando el macro de Scheme `markup`, véase Construcción de elementos de marcado en Scheme. La transformación de una expresión `\markup` en una expresión de marcado de Scheme es directa.

La instrucción nueva se puede usar como sigue:

    \markup \double-box A

Sería bueno hacer que la instrucción `double-box` fuera personalizable: aquí, los valores de relleno `box-padding` son fijos, y no se pueden cambiar por parte del usuario. Además, sería mejor distinguir la separación entre los dos rectángulos, del relleno entre el rectángulo interno y el texto. Así pues, introducimos una nueva propiedad, `inter-box-padding`, para el relleno entre los rectángulos. El `box-padding` se usará para el relleno interno. Ahora el código nuevo es como se ve a continuación:

    #(define-markup-command (double-box layout props text) (markup?)
      #:properties ((inter-box-padding 0.4)
                    (box-padding 0.6))
      "Trazar un rectángulo doble rodeando el texto."
      (interpret-markup layout props
        #{\markup \override #`(box-padding . ,inter-box-padding) \box
                   \override #`(box-padding . ,box-padding) \box
                   { #text } #}))

De nuevo, la versión equivalente que utiliza la macro de marcado sería:

    #(define-markup-command (double-box layout props text) (markup?)
      #:properties ((inter-box-padding 0.4)
                    (box-padding 0.6))
      "Trazar un rectángulo doble rodeando el texto."
      (interpret-markup layout props
        (markup #:override `(box-padding . ,inter-box-padding) #:box
                #:override `(box-padding . ,box-padding) #:box text)))

Aquí, la palabra clave `#:properties` se usa de manera que las propiedades `inter-box-padding` y `box-padding` se leen a partir del argumento `props`, y se les proporcionan unos valores predeterminados si las propiedades no están definidas.

Después estos valores se usan para sobreescribir las propiedades `box-padding` usadas por las dos instrucciones `\box`. Observe el apóstrofo invertido y la coma en el argumento de `\override`: nos permiten introducir un valor de variable dentro de una expresión literal.

Ahora, la instrucción se puede usar dentro de un elemento de marcado, y el relleno de los rectángulos se puede personalizar:

>     #(define-markup-command (double-box layout props text) (markup?)
>       #:properties ((inter-box-padding 0.4)
>                     (box-padding 0.6))
>       "Draw a double box around text."
>       (interpret-markup layout props
>         #{\markup \override #`(box-padding . ,inter-box-padding) \box
>                   \override #`(box-padding . ,box-padding) \box
>                   { #text } #}))

>     \markup \double-box A
>     \markup \override #'(inter-box-padding . 0.8) \double-box A
>     \markup \override #'(box-padding . 1.0) \double-box A

#### Extender LilyPond v2.26.0 (stable-branch).

- Appendix A Tutorial de Scheme
  - A.1 Introducción a Scheme
    - A.1.1 Cajón de arena de Scheme
    - A.1.2 Variables de Scheme
    - A.1.3 Tipos de datos simples de Scheme
    - A.1.4 Tipos de datos compuestos de Scheme
      - Parejas
      - Listas
      - Listas asociativas (listas-A)
      - Tablas de hash
    - A.1.5 Cálculos en Scheme
    - A.1.6 Procedimientos de Scheme
      - Definir procedimientos
      - Predicados
      - Valores de retorno
    - A.1.7 Condicionales de Scheme
      - if
      - cond
  - A.2 Scheme dentro de LilyPond
    - A.2.1 Sintaxis del Scheme de LilyPond
    - A.2.2 Variables de LilyPond
    - A.2.3 Depuración del código de Scheme
    - A.2.4 Variables de entrada y Scheme
    - A.2.5 Importación de Scheme dentro de LilyPond
    - A.2.6 Propiedades de los objetos
    - A.2.7 Variables de LilyPond compuestas
      - Desplazamientos
      - Fracciones
      - Dimensiones
      - Listas-A de propiedades
      - Cadenas de listas-A
    - A.2.8 El modelo de caja de LilyPond
    - A.2.9 Representación interna de la música
  - A.3 Construir funciones complicadas
    - A.3.1 Una primera aproximación (ejemplo)
    - A.3.2 Presentación de las expresiones musicales
    - A.3.3 Propiedades musicales
    - A.3.4 Duplicar una nota con ligaduras (ejemplo)
    - A.3.5 Añadir articulaciones a las notas (ejemplo)
- B Interfaces para programadores
  - B.1 Bloques de código de LilyPond
  - B.2 Funciones de Scheme
    - B.2.1 Definición de funciones de Scheme
    - B.2.2 Uso de las funciones de Scheme
    - B.2.3 Funciones de Scheme vacías
  - B.3 Funciones musicales
    - B.3.1 Definiciones de funciones musicales
    - B.3.2 Uso de las funciones musicales
    - B.3.3 Funciones de sustitución sencillas
    - B.3.4 Funciones de sustitución intermedias
    - B.3.5 Matemáticas dentro de las funciones
    - B.3.6 Funciones sin argumentos
    - B.3.7 Funciones musicales vacías
  - B.4 Funciones de eventos
  - B.5 Funciones de marcado
    - B.5.1 Construcción de elementos de marcado en Scheme
    - B.5.2 Cómo funcionan internamente los elementos de marcado
    - B.5.3 Definición de una instrucción de marcado nueva
      - Sintaxis de la definición de instrucciones de marcado
      - Acerca de las propiedades
      - Un ejemplo completo
      - Adaptación de instrucciones incorporadas
      - Convertir elementos de marcado en cadenas
    - B.5.4 Definición de nuevas instrucciones de lista de marcado
  - B.6 Contextos para programadores
    - B.6.1 Evaluación de contextos
    - B.6.2 Ejecutar una función sobre todos los objetos de la presentación
  - B.7 Funciones de callback
  - B.8 Contenedores Unpure-pure
  - B.9 Trucos difíciles
- C Interfaces de Scheme de LilyPond
- Appendix D GNU Free Documentation License
- Appendix E Índice