Manual de EEditor

Referencia completa para la aplicación EEditor y el lenguaje EELisp. Cubre cada funcionalidad, cada función integrada y cada atajo de teclado.

Índice

I. Guía del Editor

  1. Primeros pasos
  2. El Editor
  3. Barra lateral y árbol de archivos
  4. Pestañas y archivos fijados
  5. Búsqueda y apertura rápida
  6. Vista previa y exportación a PDF
  7. Notas diarias y planificador semanal
  8. Vista de calendario
  9. Barra lateral de agenda
  10. Barra lateral del REPL
  11. Bloques de código EELisp
  12. Atajos de teclado

II. El REPL

  1. Uso del REPL
  2. Comandos del REPL

III. Lenguaje EELisp

  1. Aritmética y matemáticas
  2. Comparación y lógica
  3. Variables y funciones
  4. Flujo de control
  5. Cadenas de texto
  6. Listas
  7. Diccionarios
  8. Tipos y conversión
  9. E/S y fechas
  10. Funciones del preludio
  11. HTTP y JSON
  12. Sistema de archivos
  13. Integración con el editor
  14. Portapapeles

IV. Base de datos

  1. Definición de tablas
  2. Registros y consultas
  3. Vistas interactivas
  4. Gestión de la base de datos

V. Sistema de agenda

  1. Elementos
  2. Categorías
  3. Reglas de autocategorización
  4. Vistas
  5. Consultas de calendario
  6. Entrada inteligente
  7. Elementos recurrentes y plantillas
  8. Múltiples agendas

VI. Integración

  1. Integración GUI y EELisp
Parte I — Guía del Editor

1. Primeros pasos

Cuando inicias EEditor por primera vez, ves un editor vacío con una barra lateral. Tres pasos para empezar:

  1. Abrir una carpeta — pulsa ⌘O o toca el icono de carpeta. EEditor escanea el directorio y muestra todos los archivos en el árbol de la barra lateral.
  2. Seleccionar un archivo — haz clic en cualquier archivo de la barra lateral para abrirlo en una nueva pestaña.
  3. Empezar a escribir — los cambios se guardan automáticamente tras 1 segundo de inactividad. Pulsa ⌘S para guardar inmediatamente.
Consejo: EEditor recuerda tu última carpeta abierta mediante marcadores con ámbito de seguridad. Se restaura automáticamente al reiniciar.

Abrir archivos individuales

Usa ⌘⇧O para abrir un archivo individual desde cualquier ubicación del disco. El directorio padre del archivo se convierte en la carpeta activa.

2. El Editor

EEditor proporciona un entorno de escritura libre de distracciones con resaltado de sintaxis en tiempo real para Markdown y más de 24 lenguajes de programación.

3. Barra lateral y árbol de archivos

La barra lateral muestra una vista jerárquica de tu carpeta. Los directorios se ordenan primero, luego los archivos alfabéticamente.

La barra lateral tiene tres modos mediante el control segmentado: Archivos, Calendario y Agenda.

4. Pestañas y archivos fijados

Cada archivo se abre como una pestaña en la parte superior del editor.

AcciónAtajoNotas
Siguiente pestaña⌘⌥→Vuelve al inicio
Pestaña anterior⌘⌥←Vuelve al inicio
Cerrar pestaña⌘WGuarda automáticamente si hay cambios
Cerrar todas las no fijadas⌘⌥W
Fijar / Desfijar⌘⇧KLas pestañas fijadas persisten entre sesiones

Las pestañas fijadas muestran un icono de pin, aparecen primero (ordenadas alfabéticamente) y no se pueden cerrar hasta que se desfijen. Se restauran automáticamente al reiniciar.

5. Búsqueda y apertura rápida

Búsqueda de texto completo (⌘⇧F)

Apertura rápida (⌘P)

Wiki-links (⌘O)

Coloca el cursor sobre un enlace [[nombre_archivo]] y pulsa ⌘O para abrir ese archivo directamente.

6. Vista previa y exportación a PDF

Vista previa de Markdown (⌘⇧P)

Exportación a PDF (⌘⇧E)

7. Notas diarias y planificador semanal

Nota diaria (⌘D)

Planificador semanal (⌘⇧W)

8. Vista de calendario

Cambia la barra lateral al modo Calendario usando el control segmentado.

9. Barra lateral de agenda

Cambia al modo Agenda mediante el icono del portapapeles. El panel muestra tu programación próxima en tres secciones:

Cada elemento muestra un punto de prioridad (rojo = urgente, naranja = alta, amarillo = media, gris = normal), texto, categorías y fecha formateada. Toca actualizar para recargar después de añadir elementos en el REPL.

Barra lateral del REPL

El REPL es un panel en la barra lateral derecha que coexiste con el editor. Altérnalo con ⌘⇧L o el icono de terminal en la barra de herramientas.

Bloques de código EELisp en Markdown

Incorpora código EELisp ejecutable directamente en tus archivos Markdown usando bloques de código delimitados:

```eelisp
(+ 1 2 3)
```

Ejecutar un bloque de código

  1. Coloca el cursor en cualquier lugar dentro de un bloque ```eelisp.
  2. Pulsa ⌘⇧Return (o usa el menú: Vista → Ejecutar bloque EELisp).
  3. El resultado aparece como un bloque ```result inmediatamente debajo.
```eelisp
(+ 1 2 3)
```
```result
6
```

Volver a ejecutar reemplaza el resultado existente. El resultado se inserta como texto plano (no en un bloque de código) y se selecciona automáticamente para que puedas usar ⌘C para copiar o ⌘X para cortar inmediatamente.

Formularios y tablas en el editor

Cuando un bloque EELisp devuelve un formulario (edit, defform) o una tabla (browse), se abre como un panel lateral interactivo junto al editor en lugar de insertar texto plano. Puedes interactuar con el formulario — navegar registros, editar campos, guardar — manteniendo tu documento visible. Se inserta igualmente una línea de resumen en el documento.

Los casos de uso incluyen cálculos en línea, añadir elementos de agenda desde entradas de diario, consultar datos y operaciones con archivos:

```eelisp
(add-item (smart-parse "tomorrow review quarterly report !!"))
```

```eelisp
(write-file "todo.txt" "Buy groceries\nCall dentist")
```

10. Atajos de teclado

Pulsa ⌘? en la aplicación para ver la hoja completa de atajos. Aquí está la referencia completa:

Archivos

AcciónAtajo
Nuevo archivo⌘N
Abrir carpeta⌘O
Abrir archivo⌘⇧O
Guardar⌘S
Actualizar árbol⌘⇧R
Nota diaria⌘D
Planificador semanal⌘⇧W

Navegación

AcciónAtajo
Apertura rápida⌘P
Buscar en archivos⌘⇧F
Buscar y reemplazar⌘F
Enfocar editor⌘\
Abrir wiki-link⌘O

Pestañas

AcciónAtajo
Siguiente pestaña⌘⌥→
Pestaña anterior⌘⌥←
Cerrar pestaña⌘W
Cerrar todas las no fijadas⌘⌥W
Fijar / Desfijar pestaña⌘⇧K

Edición

AcciónAtajo
Insertar marca de tiempo⌘I
Deshacer⌘Z
Rehacer⌘⇧Z

Vista y exportación

AcciónAtajo
Vista previa⌘⇧P
Exportar PDF⌘⇧E
Alternar barra lateral del REPL⌘⇧L
Enviar al REPL⌘R
Ejecutar bloque EELisp⌘⇧Return
Insertar bloque EELisp⌘⇧C
Ejecutar (en el REPL)⌘Return
Ayuda de atajos⌘?
Parte II — El REPL

11. Uso del REPL

EEditor incluye un intérprete Lisp integrado llamado EELisp — diseñado para la gestión de datos personales, cálculos y scripting.

Abrir el REPL

Evaluar expresiones

Enviar al REPL (⌘R o ⌘⇧L)

Selecciona texto en el editor y pulsa ⌘R o ⌘⇧L. La barra lateral del REPL se abre con tu selección prerrellenada en el campo de entrada, lista para que pulses ⌘Return para evaluar.

Comandos de base de datos

EELisp incluye funciones integradas y comandos del REPL para gestionar bases de datos:

ComandoDescripción
(tables)Listar todas las tablas de la base de datos actual
(describe tablename)Mostrar el esquema de una tabla
(drop-table tablename)Eliminar una tabla
:dbMostrar la ruta de la base de datos actual
:db <path>Cambiar a un archivo de base de datos diferente
:db new <name>Crear un nuevo archivo de base de datos en la carpeta actual
:db memoryCambiar a una base de datos en memoria

Cargar archivos

Usa :load path/to/file.el para cargar y evaluar un script EELisp. En iOS, toca el botón Cargar en la barra de herramientas o haz clic derecho en un archivo .el en la barra lateral.

Barra de herramientas en iOS

En iOS/iPadOS, aparece una barra de herramientas con: navegación del historial (↑/↓), fragmentos rápidos (query, deftable, defn), Cargar archivo y Limpiar.

12. Comandos del REPL

Los comandos con prefijo de dos puntos controlan el propio REPL (no son expresiones EELisp):

ComandoAliasDescripción
:help:hMostrar referencia de comandos y ejemplos rápidos
:load <file>:lCargar y evaluar un archivo .el / .lisp
:dbMostrar la ruta de la base de datos actual (:memory: o ruta de archivo)
:db <path>Cambiar a un archivo de base de datos diferente
:db new <name>Crear una nueva base de datos en la carpeta actual
:db memoryCambiar a una base de datos en memoria
:env:eListar todos los símbolos definidos en el entorno
:clear:cLimpiar el historial de salida del REPL
:reset:rReiniciar el intérprete (entorno nuevo, misma base de datos)
Conexión automática a la base de datos: Cuando abres una carpeta que contiene un archivo eelisp.db, el REPL se conecta automáticamente para almacenamiento persistente. Los datos creados con deftable e insert se guardan en disco.
Parte III — Referencia del lenguaje EELisp

13. Aritmética y matemáticas

Todos los operadores aritméticos son variádicos (aceptan múltiples argumentos) y funcionan con enteros y decimales.

FunciónFirmaDescripción
+(+ num ...)Suma. (+ 1 2 3)6
-(- num ...)Resta o negación. (- 10 3)7, (- 5)-5
*(* num ...)Multiplicación. (* 2 3 4)24
/(/ num num ...)División. (/ 100 3)33.333...
mod(mod a b)Módulo. (mod 10 3)1
abs(abs num)Valor absoluto. (abs -42)42
min(min num ...)Mínimo. (min 3 1 4)1
max(max num ...)Máximo. (max 3 1 4)4
floor(floor num)Redondear hacia abajo. (floor 3.7)3
ceil(ceil num)Redondear hacia arriba. (ceil 3.2)4
pow(pow base exp)Exponenciación. (pow 2 10)1024
round(round num [places])Redondear. (round 3.14159 2)3.14
;; Ejemplos aritméticos
(+ 1 2 3 4)            ; → 10
(* 6 7)                ; → 42
(/ 100 3)              ; → 33.333...
(pow 2 10)             ; → 1024
(round 3.14159 2)     ; → 3.14

;; Anidamiento
(+ (* 3 4) (- 10 5))    ; → 17

14. Comparación y lógica

FunciónFirmaDescripción
=(= a b)Igualdad. Funciona con números, cadenas, booleanos
!=(!= a b)Desigualdad
<(< a b)Menor que
>(> a b)Mayor que
<=(<= a b)Menor o igual que
>=(>= a b)Mayor o igual que

Operadores lógicos

Estas son formas especiales (evaluación en cortocircuito):

(and true false)        ; → false
(or  false true)        ; → true
(not true)              ; → false

;; Cortocircuito: (or) devuelve el primer valor verdadero
(or nil false 42 99)    ; → 42

15. Variables y funciones

Definir variables

(def x 42)
(def greeting "Hello, world!")
(def pi 3.14159)

Definir funciones

(defn square (x)
  (* x x))

(square 5)  ; → 25

;; Cuerpo con múltiples expresiones (se devuelve el último valor)
(defn greet (name)
  (def msg (str "Hello, " name "!"))
  (println msg)
  msg)

Funciones anónimas

(map (fn (x) (* x x)) '(1 2 3))  ; → (1 4 9)

Parámetros rest

(defn sum (first . rest)
  (reduce + first rest))

(sum 1 2 3 4 5)  ; → 15

Enlaces locales

(let ((x 1) (y 2))
  (+ x y))  ; → 3

16. Flujo de control

if

(if (> x 0) "positive" "non-positive")

cond

(cond
  (< x 0)  "negative"
  (= x 0)  "zero"
  else     "positive")

when

;; Ejecutar el cuerpo solo si la condición es verdadera
(when (> x 0)
  (println "positive!")
  x)

loop / recur

;; Sumar de 0 a 10
(loop ((i 0) (acc 0))
  (> i 10)
  (recur (+ i 1) (+ acc i)))  ; → 55

begin

;; Evaluar múltiples expresiones, devolver la última
(begin
  (def a 10)
  (def b 20)
  (+ a b))  ; → 30

17. Cadenas de texto

FunciónFirmaEjemplo → Resultado
str(str val ...)(str "a" "b" "c")"abc"
str-len(str-len s)(str-len "hello")5
str-upper(str-upper s)(str-upper "hello")"HELLO"
str-lower(str-lower s)(str-lower "HELLO")"hello"
str-contains(str-contains s sub)(str-contains "hello" "ell")true
str-starts-with(str-starts-with s prefix)(str-starts-with "hello" "he")true
str-ends-with(str-ends-with s suffix)(str-ends-with "hello" "lo")true
str-split(str-split s sep)(str-split "a,b,c" ",")("a" "b" "c")
str-join(str-join sep list)(str-join "-" '("a" "b"))"a-b"
str-trim(str-trim s)(str-trim " hi ")"hi"
str-replace(str-replace s target repl)(str-replace "hello" "l" "r")"herro"
str-matches(str-matches s regex)Devuelve la lista de grupos de captura o nil
substr(substr s start [end])(substr "hello" 1 3)"el"

18. Listas

FunciónFirmaEjemplo → Resultado
list(list val ...)(list 1 2 3)(1 2 3)
cons(cons val list)(cons 0 '(1 2))(0 1 2)
car / head(car list)(car '(1 2 3))1
cdr / tail(cdr list)(cdr '(1 2 3))(2 3)
nth(nth list n)(nth '(a b c) 1)b
length(length seq)(length '(1 2 3))3
append(append list ...)(append '(1) '(2 3))(1 2 3)
reverse(reverse list)(reverse '(1 2 3))(3 2 1)
map(map fn list)(map inc '(1 2 3))(2 3 4)
filter(filter fn list)(filter even? '(1 2 3 4))(2 4)
reduce(reduce fn init list)(reduce + 0 '(1 2 3))6
range(range [start] end [step])(range 1 6)(1 2 3 4 5)
flatten(flatten list)(flatten '(1 (2 3) (4)))(1 2 3 4)
sort-by(sort-by fn list)(sort-by id '(3 1 2))(1 2 3)
zip(zip list list)(zip '(1 2) '(a b))((1 a) (2 b))
empty?(empty? val)(empty? '())true
;; Encadenar operaciones de listas
(def nums (range 1 11))
(filter even? nums)            ; → (2 4 6 8 10)
(map (fn (x) (* x x))
     (filter even? nums))       ; → (4 16 36 64 100)
(reduce + 0 (range 1 101))   ; → 5050

19. Diccionarios

Los diccionarios usan claves de tipo keyword (:name) y son inmutables — las operaciones devuelven nuevos diccionarios.

FunciónFirmaEjemplo → Resultado
dict(dict :key val ...)(dict :a 1 :b 2){:a 1 :b 2}
dict-get(dict-get d key [default])(dict-get d :name) → valor o nil
dict-set(dict-set d key val)Devuelve un nuevo diccionario con la clave establecida
dict-keys(dict-keys d)(dict-keys {:a 1 :b 2})(:a :b)
dict-values(dict-values d)(dict-values {:a 1 :b 2})(1 2)
dict-has(dict-has d key)(dict-has {:a 1} :a)true
dict-merge(dict-merge d ...)Fusiona diccionarios; las claves posteriores tienen prioridad
(def person {:name "Alice" :age 30})
(dict-get person :name)          ; → "Alice"
(dict-set person :age 31)        ; → {:name "Alice" :age 31}
(dict-merge person {:city "NYC"}) ; → {:name "Alice" :age 30 :city "NYC"}

20. Tipos y conversión

Predicados de tipo

FunciónDevuelve verdadero cuando
string?El valor es una cadena de texto
number?El valor es un número
bool?El valor es un booleano
list?El valor es una lista
nil?El valor es nil/null
symbol?El valor es un símbolo
keyword?El valor es una keyword
fn?El valor es una función
dict?El valor es un diccionario
date?El valor es una fecha
record?El valor es un registro de base de datos
item?El valor es un elemento de agenda

Inspección de tipos

(type 42)          ; → "number"
(type "hello")     ; → "string"
(type '(1 2))      ; → "list"

Funciones de conversión

FunciónDescripción
->stringConvertir cualquier valor a su representación en cadena de texto
->numberConvertir cadena a número, booleano a 0/1
->boolVeracidad: nil, false, 0, "" → false; todo lo demás → true

21. E/S & Fechas

Salida

FunciónDescripción
(print val ...)Imprime valores sin salto de línea final
(println val ...)Imprime valores con salto de línea final

Funciones de fecha

FunciónFirmaDescripción
now(now)Objeto de fecha/hora actual
today(today)Hoy como cadena ISO "YYYY-MM-DD"
date-format(date-format date [fmt])Formatea una fecha. Por defecto: "yyyy-MM-dd HH:mm"
date-add(date-add date n :unit)Añade días/semanas/meses. Unidades: :days, :weeks, :months
date-diff(date-diff d1 d2)Diferencia en días entre dos cadenas de fecha ISO
(today)                              ; → "2026-02-23"
(date-add (today) 7 :days)          ; → "2026-03-02"
(date-add "2026-01-31" 1 :months)   ; → "2026-02-28"
(date-diff "2026-01-01" "2026-12-31") ; → 364

22. Funciones del Preludio

Estas funciones están definidas en el propio EELisp y se cargan automáticamente al inicio:

FunciónDescripciónEjemplo
incIncrementar en 1(inc 5)6
decDecrementar en 1(dec 5)4
even?Verdadero si es par(even? 4)true
odd?Verdadero si es impar(odd? 3)true
zero?Verdadero si es cero(zero? 0)true
pos?Verdadero si es positivo(pos? 5)true
neg?Verdadero si es negativo(neg? -3)true
firstPrimer elemento(first '(a b c))a
secondSegundo elemento(second '(a b c))b
thirdTercer elemento(third '(a b c))c
lastÚltimo elemento(last '(a b c))c
takeTomar los primeros n(take 2 '(a b c))(a b)
dropDescartar los primeros n(drop 1 '(a b c))(b c)
some?¿Alguna coincidencia?(some? even? '(1 2 3))true
every?¿Todas coinciden?(every? pos? '(1 2 3))true
pipeEncadenamiento(pipe 5 inc inc square)49
composeComponer funciones((compose inc square) 5)26
partialAplicación parcial((partial + 10) 5)15
idFunción identidad(id 42)42

23. HTTP & JSON

FunciónFirmaDescripción
http-get(http-get url)Petición GET. Devuelve {:status N :body "..."}
http-post(http-post url body [:content-type "..."])Petición POST con cuerpo
json-parse(json-parse string)Analiza JSON a diccionario/lista de EELisp
json-stringify(json-stringify value)Convierte un valor de EELisp a cadena JSON
;; Obtener datos de una API
(def resp (http-get "https://api.example.com/data"))
(def data (json-parse (dict-get resp :body)))

;; Enviar JSON
(http-post "https://api.example.com/items"
  (json-stringify {:name "test"})
  :content-type "application/json")

Evaluación

FunciónDescripción
(eval expr)Evalúa una expresión no evaluada
(parse string)Analiza una cadena como código EELisp

Sistema de Archivos

EELisp puede leer y escribir archivos en la carpeta abierta. Todas las rutas son relativas al directorio del espacio de trabajo actual.

FunciónDescripción
(read-file path)Lee el contenido de un archivo como cadena
(write-file path content)Escribe contenido en un archivo (crea o sobrescribe)
(append-file path content)Añade contenido a un archivo existente
(file-exists? path)Comprueba si un archivo existe
(list-files [path])Lista los nombres de archivos en un directorio (por defecto: raíz del espacio de trabajo)
(current-dir)Obtiene la ruta raíz del espacio de trabajo
;; Leer un archivo
(def content (read-file "notes.md"))

;; Escribir resultados en un archivo
(write-file "output.txt" (str "Report: " (today)))

;; Añadir a un registro
(append-file "log.txt" (str (today) " - Done\n"))

;; Listar archivos del espacio de trabajo
(list-files)       ; → ("README.md" "notes.md" ...)
(list-files "src") ; → ("main.el" "utils.el" ...)

Integración con el Editor

Estas funciones nativas permiten que el código EELisp interactúe con el búfer del editor activo.

FunciónDescripción
(cursor-pos)Obtiene la posición actual del cursor (desplazamiento en caracteres)
(set-cursor-pos pos)Mueve el cursor a una posición
(insert-at pos text)Inserta texto en una posición
(replace-range start end text)Reemplaza texto entre inicio y fin
(selection)Obtiene el texto seleccionado actualmente (o nil)
(current-file)Obtiene la ruta del archivo activo
(buffer-text)Obtiene el texto completo del editor activo
;; Insertar texto en el cursor
(insert-at (cursor-pos) (str "Updated: " (today)))

;; Obtener lo seleccionado
(def sel (selection))

;; Leer el búfer completo
(def text (buffer-text))
(println (str "Length: " (str-len text)))

Portapapeles

FunciónDescripción
(clipboard-get)Lee texto del portapapeles
(clipboard-set text)Copia texto al portapapeles
;; Copiar un resultado al portapapeles
(clipboard-set (str "Total: $" (reduce + 0 '(10 20 30))))

;; Pegar y procesar el contenido del portapapeles
(str-upper (clipboard-get))
Parte IV — Referencia de Base de Datos

24. Definición de Tablas

EELisp incluye un motor de base de datos SQLite integrado. Las tablas se definen con esquemas tipados.

Sintaxis básica

(deftable contacts (name:string email:string age:number))

Tipos de campo

TipoDescripciónValores de ejemplo
stringDatos de texto"Alice", "hello@example.com"
numberEntero o decimal42, 3.14
boolBooleanotrue, false
dateCadena de fecha ISO"2026-02-23"
memoTexto largoContenido multilínea
choiceSelector desplegableLista de opciones predefinidas

Gestión de tablas

FunciónDescripción
(tables)Lista todos los nombres de tablas
(describe table)Muestra el esquema de la tabla
(drop-table table)Elimina una tabla y todos sus datos
(pack table)Elimina permanentemente los registros borrados de forma lógica
;; Ejemplo completo
(deftable tasks (title:string priority:number done:bool due:date))
(tables)       ; → (tasks)
(describe tasks) ; → detalles del esquema

25. Registros & Consultas

Inserción de registros

(insert tasks {:title "Write docs" :priority 1 :done false})
(insert tasks {:title "Fix bug" :priority 2 :done false :due "2026-03-01"})

Consultas

;; Todos los registros
(query tasks)

;; Con cláusula WHERE
(query tasks :where "priority <= ?" :params (list 2))

;; Ordenados y limitados
(query tasks :order "priority" :limit 5)

;; Seleccionar columnas específicas
(query tasks :select "title, done")

;; Orden descendente
(query tasks :order "priority" :asc false)

Actualización y eliminación

;; Actualizar por ID
(update tasks 1 {:done true})

;; Borrado lógico (estilo dBASE, se puede recuperar)
(delete tasks 1)

;; Eliminar permanentemente los registros borrados lógicamente
(pack tasks)

;; Contar registros
(count-records tasks)
(count-records tasks :where "done = ?" :params (list false))

Acceso a registros

FunciónDescripción
(field-get record :field)Obtiene el valor de un campo de un registro
(field-set record :field val)Devuelve un nuevo registro con el campo actualizado
(record-id record)Obtiene el ID numérico del registro
(records result-set)Extrae la lista de registros de un resultado de consulta
;; Trabajar con resultados de consulta programáticamente
(def results (query tasks :where "done = ?" :params (list false)))
(def recs (records results))
(map (fn (r) (field-get r :title)) recs)  ; → ("Write docs" "Fix bug")

26. Vistas Interactivas

EELisp puede renderizar componentes de interfaz interactivos directamente en la salida del REPL.

Browse (vista de tabla)

;; Explorar todos los registros en una cuadrícula desplazable
(browse tasks)

;; Con filtros y ordenación
(browse tasks :where "done = ?" :params (list false) :order "priority")

Edit (formulario CRUD)

;; Abrir un formulario interactivo para crear/leer/actualizar/eliminar
(edit tasks)

;; Con filtros
(edit tasks :where "priority = ?" :params (list 1))

El formulario muestra un registro a la vez con navegación Anterior/Siguiente, edición en línea, y botones Guardar, Nuevo y Eliminar.

Formularios calculados (defform)

;; Formulario calculador independiente con campos calculados
(defform loan-calc
  (principal:number rate:number years:number)
  :computed (
    (monthly-payment
      (let ((r (/ rate 1200))
            (n (* years 12)))
        (round (/ (* principal r (pow (+ 1 r) n))
                  (- (pow (+ 1 r) n) 1)) 2)))
    (total-paid
      (round (* monthly-payment (* years 12)) 2))))

Los campos calculados se actualizan automáticamente cuando cambian los campos de entrada.

Campos de selección (desplegable)

Usa la sintaxis (name:choice "opt1" "opt2" ...) para crear un selector desplegable:

(defform new-task
  (title:string
   (priority:choice "low" "medium" "high" "urgent")
   (status:choice "todo" "in-progress" "done")
   notes:memo))

Los campos de selección se renderizan como un menú desplegable en la interfaz del formulario.

Formularios vinculados a tablas (:source)

Vincula un formulario a una tabla de base de datos existente con :source para habilitar CRUD completo:

;; Crear una tabla primero
(deftable projects (name:string status:string budget:number))
(insert projects {:name "Alpha" :status "active" :budget 50000})

;; Formulario respaldado por la tabla con desplegable para estado
(defform project-editor
  (name:string
   (status:choice "planning" "active" "completed")
   budget:number)
  :source projects)

El formulario carga registros de la tabla de origen con navegación Anterior/Siguiente, y botones Guardar, Nuevo y Eliminar — como (edit table) pero con tipos de campo personalizados.

27. Gestión de Base de Datos

Conexión automática

Comandos de base de datos del REPL

ComandoDescripción
:dbMuestra la ruta de la base de datos actual
:db <path>Cambia a un archivo de base de datos diferente (relativo a la carpeta)
:db new <name>Crea una nueva base de datos en la carpeta actual
:db memoryCambia a una base de datos en memoria
Consejo: Las rutas de base de datos son relativas a la carpeta abierta actualmente. Usa :db mydata.db en lugar de escribir la ruta completa.
Parte V — Sistema de Agenda

28. Elementos

El sistema de agenda es un gestor de información personal inspirado en Lotus Agenda. Los elementos son entradas de texto libre con metadatos opcionales.

Añadir elementos

(add-item "Finish quarterly report")

;; Con metadatos
(add-item "Call dentist" :when "2026-03-01" :priority 2)
(add-item "Buy groceries" :category "personal" :notes "milk, eggs")

;; Añadir con la fecha de hoy
(add-item-today "Review pull requests" :priority 1)

Consultar elementos

(items)                          ; todos los elementos (vista de tabla)
(items :category "work")        ; filtrar por categoría
(items :search "quarterly")     ; búsqueda de texto
(items :priority 1)             ; filtrar por prioridad
(items :when-before "2026-03-01") ; con fecha anterior a

Gestionar elementos

FunciónDescripción
(item-get id)Obtiene un solo elemento por ID
(item-edit id)Abre el elemento en vista de formulario para edición
(item-set id :field val ...)Actualiza los campos del elemento
(item-done id)Marca el elemento como completado (borrado lógico)
(item-count)Cuenta todos los elementos
(item-count :category "work")Cuenta los elementos de una categoría

29. Categorías

Las categorías son jerárquicas (usan separadores /) y opcionalmente exclusivas (un elemento solo puede estar en una hija).

;; Categorías jerárquicas
(defcategory work)
(defcategory work/projects)
(defcategory work/meetings)
(defcategory personal)
(defcategory personal/errands)

;; Exclusiva: el elemento solo puede estar en una hija
(defcategory priority :exclusive true
  :children (high medium low))

;; Asignar / desasignar
(assign 1 "work/projects")
(assign 1 "priority/high")
(unassign 1 "personal")

;; Ver el árbol de categorías
(categories)
Consejo: Cuando un padre es :exclusive true, asignar una hija (p. ej., priority/low) elimina automáticamente las hermanas (p. ej., priority/high). Perfecto para estado, prioridad o cualquier agrupación de selección única.

30. Reglas de Auto-Categorización

Las reglas categorizan automáticamente los elementos basándose en su contenido — la función estrella de Lotus Agenda.

;; Reglas de coincidencia de texto
(defrule urgent-flag
  :when (str-contains text "URGENT")
  :assign "priority/high")

(defrule meeting-detect
  :when (or (str-contains text "meeting")
            (str-contains text "call with"))
  :assign "work/meetings")

;; Regex con extracción de fechas
(defrule date-extract
  :when (str-matches text "\\b(\\d{4}-\\d{2}-\\d{2})\\b")
  :action (item-set id :when (match 1)))

;; Aplicar reglas
(apply-rules)      ; aplicar en lote a todos los elementos
(apply-rules 42)   ; aplicar al elemento #42

;; Auto-aplicar en cada add-item
(auto-categorize true)

Gestión de reglas

FunciónDescripción
(rules)Lista todas las reglas definidas
(drop-rule name)Elimina una regla
(auto-categorize bool)Activa/desactiva la auto-aplicación al insertar
Contexto de las reglas: Las condiciones tienen acceso a text, notes, categories, todas las propiedades del elemento, además de funciones auxiliares como has-category y overdue?. Combínalas con and/or/not.

31. Vistas

Las vistas son consultas guardadas que filtran, ordenan y agrupan elementos dinámicamente.

(defview work-board
  :source items
  :filter (has-category "work")
  :group-by category
  :sort-by when)

(defview urgent
  :source items
  :filter (= priority "1")
  :sort-by when)

(defview inbox
  :source items
  :filter (= (length categories) 0))

;; Mostrar una vista
(show work-board)
(show urgent)
FunciónDescripción
(views)Lista todas las vistas definidas
(drop-view name)Elimina una vista

32. Consultas de Calendario

;; Elementos para una fecha específica
(items-on "2026-02-24")

;; Elementos en un rango de fechas
(items-between "2026-02-24" "2026-02-28")

;; Usando funciones auxiliares de fecha
(items-on (today))
(items-between (today) (date-add (today) 7 :days))
Consejo: La barra lateral del Calendario y la barra lateral de Agenda en la interfaz gráfica usan estas mismas funciones internamente. Añade elementos en el REPL y luego cambia al modo Calendario o Agenda para verlos visualmente.

33. Entrada Inteligente

El comando add analiza lenguaje natural para extraer fechas, prioridades y personas automáticamente.

(add "Meet Alice tomorrow for coffee !!")
; → :when = tomorrow, :priority 2, :who "Alice"

(add "Call Bob next Monday about the project")
; → :when = next Monday, :who "Bob"

(add "URGENT fix server crash")
; → :priority 1

;; Vista previa sin crear
(smart-parse "email Sarah March 15 about renewal !!")
; → {:text "email Sarah about renewal" :when "2026-03-15" :priority 2 :who ("Sarah")}

Patrones reconocidos

34. Elementos Recurrentes & Plantillas

Recurrencia

;; Intervalos integrados
(add-item "Team standup" :when (today) :recur :daily)
(add-item "Weekly review" :when (today) :recur :weekly)
(add-item "Monthly report" :when (today) :recur :monthly)

;; Intervalo personalizado
(add-item "Check filters" :when (today) :recur (every 3 :months))

;; Al marcar como completado, la siguiente ocurrencia se crea automáticamente
(item-done 1)  ; crea la siguiente recurrencia automáticamente

Plantillas

;; Definir un modelo de elemento reutilizable
(deftemplate weekly-review
  :text "Weekly review"
  :category "work"
  :priority 2
  :recur :weekly)

;; Crear a partir de plantilla con modificaciones
(from-template weekly-review :when "2026-03-01")

;; Gestionar plantillas
(templates)           ; listar todas
(drop-template weekly-review)  ; eliminar

35. Múltiples Agendas

Abre, cambia entre y gestiona múltiples bases de datos de agenda. Útil para separar agendas de trabajo y personales.

;; Abrir una nueva agenda
(open-agenda "work.db")
(open-agenda "personal.db")

;; Cambiar entre agendas
(use-agenda "work")

;; Listar todas las agendas abiertas
(agendas)  ; muestra el marcador activo (*)

;; Cerrar una agenda
(close-agenda "personal")

Exportar e Importar

;; Exportar para copia de seguridad o migración
(export-agenda "work" :format :json :path "work-backup.json")

;; Importar desde una exportación anterior
(import-agenda "work-backup.json")
Parte VI — Integración

36. Integración GUI & EELisp

La interfaz gráfica de EEditor se integra con EELisp a través del método eval() del intérprete. Todo el flujo de datos pasa por expresiones EELisp — la interfaz gráfica nunca accede directamente a SQLite.

Arquitectura

┌─────────────────────────┐
│  Vistas SwiftUI          │
│  (Barra lateral, Calendario, │
│   Agenda, REPL)         │
├─────────────────────────┤
│  ViewModels             │
│  (llaman a interpreter.eval)│
├─────────────────────────┤
│  Intérprete EELisp      │
│  (builtins, preludio)   │
├─────────────────────────┤
│  Base de datos SQLite   │
│  (eelisp.db)            │
└─────────────────────────┘

Cómo funciona

Ejemplo de flujo de datos

;; 1. El usuario añade elementos en el REPL
(add-item "Review PRs" :when (today) :priority 1)

;; 2. Cambiar a la barra lateral de Agenda → la GUI llama a:
;;    interpreter.eval("(items-between startKey endKey)")
;;    Analiza los resultados en estructuras AgendaDisplayItem

;; 3. Cambiar al Calendario → la GUI llama a:
;;    interpreter.eval("(items-on \"2026-02-23\")")
;;    Cuenta los elementos por día para los indicadores de puntos
Principio clave: La interfaz gráfica es una capa de presentación ligera. Toda la lógica de negocio — esquemas de tablas, consultas, reglas de agenda, vistas — reside en EELisp. Esto significa que puedes programar y automatizar todo desde el REPL.

Consejos para iOS e iPadOS